井字游戏:内容周期
让我们尝试将Celery / RabbitMQ连接到我们的项目。 作为基础,请与Flask进行一个项目 。 芹菜将进行随机数计算。
项目安装
我们在您的计算机上克隆项目:
git clone https://github.com/nomhoi/tic-tac-toe-part6.git
发射容器:
cd tic-tac-toe-part6 docker-compose up -d
我们构建Web应用程序:
cd front npm install npm run-script build
在http:// localhost打开浏览器。
Docker容器
Nginx服务保持不变。 在flask服务中,他们将Celery软件包安装添加到了requirements.txt文件中,并使用Celery项目源安装了该文件夹:
volumes: - ./flask:/code - ./celery/app/proj:/code/proj
增加了新的芹菜和兔子服务。
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
芹菜服务
Celery服务基于本教程 。 那些不熟悉Celery的人,可以在这里仔细阅读本教程:
$ 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> >>>
如您所见,我们在Celery中的项目被设计为项目包。 在Celery任务中,我们的getnumber任务已添加到task.py文件中 :
@app.task def getnumber(): return randrange(9)
烧瓶服务
让我提醒您,我们已将Celery软件包添加到此服务中,并使用proj项目安装了该文件夹。 该项目的源代码现在存在于flask和celery这两个服务中 。
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)
在数字处理程序中,我们调用getnumber任务,该任务在celery worker中运行,并返回任务标识符。 在结果处理程序中,我们通过标识符获取完成任务的结果,并以前端JSON格式返回响应。
前端
在游戏管理器中,通过单击“ 获取随机数”按钮,我们首先向地址/数字处的后端发送请求,并从中获取Celery任务ID。 之后,在getResult函数中, 我们会定期向后端发送请求,以在地址/ 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); }
将查询结果的输出更改为后端:
{#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}
家庭作业
实际上,现在的结果是在第一个请求之后立即产生的。 尝试让生活在芹菜中的聪明经纪人考虑周全,以免立即给出答案。
有时会从烧瓶 'a(500(INTERNAL SERVER ERROR))开始出现错误,这会引发异常“ celery.exceptions.TimeoutError:操作超时。”在celery中 。 只有重新启动服务才有帮助。 在不深入探究问题的同时,请看一看。
GetResult仅以SUCCESS状态处理响应;在其他情况下,将发出第二个请求。 您可以使用FAILURE和PENDING添加响应处理。 结果处理程序中响应的形成也可能取决于任务的状态。
您可以尝试连接Redis,而不是RabbitMQ消息代理。
您可以尝试通过消息代理执行来自应用程序的请求。
并且还尝试根据Boost.Beast示例进行操作。
GitHub存储库
https://github.com/nomhoi/tic-tac-toe-part6