Tic Tac Toe: Ciclo do Conteúdo
Vamos tentar conectar o Celery / RabbitMQ ao nosso projeto. Como base, faça um projeto com o Flask . O aipo fará o cálculo do número aleatório.
Instalação do Projeto
Clonamos o projeto no seu computador:
git clone https://github.com/nomhoi/tic-tac-toe-part6.git
Lançar contêineres:
cd tic-tac-toe-part6 docker-compose up -d
Criamos o aplicativo da web:
cd front npm install npm run-script build
Abra o navegador em http: // localhost .
Contentores Docker
O serviço nginx permaneceu inalterado. No serviço de balão , eles adicionaram a instalação do pacote Celery ao arquivo requirements.txt e montaram a pasta com a fonte do projeto Celery:
volumes: - ./flask:/code - ./celery/app/proj:/code/proj
Novos serviços de aipo e coelho foram adicionados .
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
Serviço de aipo
O serviço de aipo é baseado neste tutorial . Para aqueles que não estão familiarizados com o aipo, faz sentido seguir este tutorial aqui:
$ 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> >>>
Como você pode ver, nosso projeto no Aipo é projetado como um pacote de proj . Nas tarefas do aipo, nossa tarefa getnumber foi adicionada ao arquivo tasks.py :
@app.task def getnumber(): return randrange(9)
Serviço de balão
Deixe-me lembrá-lo de que adicionamos o pacote Aipo a este serviço e montamos a pasta com o projeto proj . O código fonte deste projeto agora está presente em dois serviços, balão e aipo .
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)
No manipulador de números , chamamos a tarefa getnumber , que é executada no operador de aipo e retorna o identificador da tarefa. No manipulador de resultados , obtemos o resultado da tarefa concluída pelo identificador e retornamos a resposta no formato JSON do front end.
Frontend
No gerenciador do nosso jogo, clicando no botão Obter número aleatório , primeiro enviamos uma solicitação para o back-end no endereço / número e obtemos o ID da tarefa do aipo. Depois disso, na função getResult , enviamos periodicamente uma solicitação ao back-end para receber o resultado no endereço / resultado / <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); }
Alterou a saída dos resultados das consultas para o back-end:
{#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}
Lição de casa
De fato, agora o resultado vem imediatamente após a primeira solicitação. Experimente o nosso agente inteligente que vive no aipo para ficar um pouco pensativo, para não dar uma resposta imediata.
De tempos em tempos, começa um erro vindo do balão 'a "500 (INTERNO SERVER ERROR)", isso gera a exceção "celery.exceptions.TimeoutError: a operação expirou." No aipo . Somente serviços de reinicialização ajudam. Enquanto não estiver cavando o que há, dê uma olhada.
GetResult processa a resposta apenas com o estado SUCCESS; em outros casos, uma segunda solicitação é feita. Você pode adicionar manipulação de resposta com FAILURE e PENDING. A formação da resposta no manipulador de resultados também pode depender do estado da tarefa.
Em vez do intermediário de mensagens RabbitMQ, você pode tentar conectar o Redis.
Você pode tentar executar solicitações do aplicativo por meio de intermediários de mensagens.
E também tente fazê-lo com base no exemplo Boost.Beast.
Repositório do GitHub
https://github.com/nomhoi/tic-tac-toe-part6