Tic Tac Toe: Cycle de contenu
Essayons de connecter Celery / RabbitMQ à notre projet. Comme base, prenez un projet avec Flask . Le céleri fera le calcul du nombre aléatoire.
Installation du projet
Nous clonons le projet sur votre ordinateur:
git clone https://github.com/nomhoi/tic-tac-toe-part6.git
Lancement de conteneurs:
cd tic-tac-toe-part6 docker-compose up -d
Nous construisons l'application web:
cd front npm install npm run-script build
Ouvrez le navigateur Ă http: // localhost .
Conteneurs Docker
Le service nginx est resté inchangé. Dans le service flask , nous avons ajouté l'installation du package Celery au fichier requirements.txt et monté le dossier avec la source du projet Celery:
volumes: - ./flask:/code - ./celery/app/proj:/code/proj
De nouveaux services de céleri et de lapin ont été ajoutés .
celery: container_name: celery build: context: celery/ dockerfile: Dockerfile volumes: - ./celery/app:/app depends_on: - rabbit networks: - backend rabbit: container_name: rabbit hostname: rabbit image: rabbitmq:3.7.15-alpine environment: - RABBITMQ_DEFAULT_USER=admin - RABBITMQ_DEFAULT_PASS=CT2gNABH8eJ9yVh ports: - "5672:5672" networks: - backend
Service de céleri
Le service Céleri est basé sur ce tutoriel . Ceux qui ne connaissent pas le céleri, il est logique de parcourir ce tutoriel ici:
$ docker exec -it celery python Python 3.7.3 (default, May 11 2019, 02:00:41) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from proj.tasks import add >>> add.delay(2, 2) <AsyncResult: 43662174-657f-4dd3-ab1a-22f5950c8794> >>>
Comme vous pouvez le voir, notre projet dans Celery est conçu comme un package proj . Notre tâche getnumber a été ajoutée aux tâches Celery dans le fichier tasks.py:
@app.task def getnumber(): return randrange(9)
Service de flacon
Permettez-moi de vous rappeler que nous avons ajouté le package Celery à ce service et monté le dossier avec le projet proj . Le code source de ce projet est maintenant présent dans deux services, flacon et céleri .
from flask import Flask, jsonify from proj.tasks import getnumber from proj.celery import app as celery app = Flask(__name__) @app.route('/number') def number(): task = getnumber.delay() return task.id @app.route('/result/<task_id>') def result(task_id): task = getnumber.AsyncResult(task_id) result = task.get(timeout = 3) response = { 'state': task.state, 'number': result, } return jsonify(response)
Dans le gestionnaire de numéros , nous appelons la tâche getnumber , qui s'exécute dans le céleri , et renvoie l'identifiant de la tâche. Dans le gestionnaire de résultats , nous obtenons le résultat de la tâche terminée par identifiant et retournons la réponse au format JSON frontal.
Frontend
Dans le gestionnaire de notre jeu, en cliquant sur le bouton Obtenir un numéro aléatoire , nous envoyons d'abord une demande au backend à l'adresse / numéro et en obtenons l'ID de tâche Céleri. Après cela, dans la fonction getResult , nous envoyons périodiquement une requête au backend pour recevoir le résultat à l'adresse / result / <task_id> .
async function getResult(task_id) { var i = 1; var timerId = setTimeout(async function go() { console.log("Result request: " + i); console.log("Task Id: " + task_id) const res = await fetch(`result/` + task_id); const response = await res.text(); if (res.ok) { let result = JSON.parse(response); console.log(result) if (result.state === 'SUCCESS') { let i = parseInt(result.number); if ($status === 1 || $history.state.squares[i]) { promise_number = result.number + ' - busy'; return; } promise_number = i; history.push(new Command($history.state, i)); return; } } if (i < 5) setTimeout(go, 500); i++; }, 500); }
Modification de la sortie des résultats des requêtes vers le backend:
{#await promise} <p>...</p> {:then taskid} <p>Task Id: {taskid}</p> {:catch error} <p style="color: red">{error.message}</p> {/await} {#await promise_number} <p>...</p> {:then number} <p>Number: {number}</p> {:catch error} <p style="color: red">{error.message}</p> {/await}
Devoirs
En fait, maintenant le résultat vient immédiatement après la première demande. Essayez notre agent intelligent vivant dans le céleri pour faire un peu attentionné, afin de ne pas donner immédiatement une réponse.
De temps en temps, une erreur commence à provenir du flacon 'a "500 (ERREUR DE SERVEUR INTERNE)", ce qui déclenche l'exception "celery.exceptions.TimeoutError: l'opération a expiré." Dans le céleri . Seuls les services de redémarrage sont utiles. Sans creuser le problème, jetez un œil.
GetResult traite la réponse uniquement avec l'état SUCCESS; dans d'autres cas, une deuxième demande est effectuée. Vous pouvez ajouter la gestion des réponses avec FAILURE et PENDING. La formation de la réponse dans le gestionnaire de résultats peut également dépendre de l'état de la tâche.
Au lieu du courtier de messages RabbitMQ, vous pouvez essayer de connecter Redis.
Vous pouvez essayer d'exécuter des demandes à partir de l'application via des courtiers de messages.
Et essayez également de le faire sur la base de l'exemple Boost.Beast.
Dépôt GitHub
https://github.com/nomhoi/tic-tac-toe-part6