首先,让我们澄清一下 celery 库(通过 pip install 或 setup.py 获得)和 celery worker 之间的区别 - 这是从代理和处理它们。当然,您可能希望拥有多个 workers/进程(例如,用于将不同的任务分配给不同的 worker)。
假设您有两个任务:calculate_recommendations_task 和 periodic_update_task,并且您想在单独的工作人员(即 recommendation_worker 和 periodic_worker)上运行它们。
另一个进程将是 celery beat,它只是每 x 小时将 periodic_update_task 排入代理。
此外,假设您有一个使用bottle 实现的简单网络服务器。
我假设您也想将 celery 代理和后端与 docker 一起使用,我将选择 celery 的推荐用法 - RabbitMQ 作为代理,Redis 作为后端。
所以现在我们有 6 个容器,我会将它们写在 docker-compose.yml 中:
version: '2'
services:
rabbit:
image: rabbitmq:3-management
ports:
- "15672:15672"
- "5672:5672"
environment:
- RABBITMQ_DEFAULT_VHOST=vhost
- RABBITMQ_DEFAULT_USER=guest
- RABBITMQ_DEFAULT_PASS=guest
redis:
image: library/redis
command: redis-server /usr/local/etc/redis/redis.conf
expose:
- "6379"
ports:
- "6379:6379"
recommendation_worker:
image: recommendation_image
command: celery worker -A recommendation.celeryapp:app -l info -Q recommendation_worker -c 1 -n recommendation_worker@%h -Ofair
periodic_worker:
image: recommendation_image
command: celery worker -A recommendation.celeryapp:app -l info -Q periodic_worker -c 1 -n periodic_worker@%h -Ofair
beat:
image: recommendation_image
command: <not sure>
web:
image: web_image
command: python web_server.py
构建recommendation_image 和web_image 的dockerfile 都应该安装celery 库。只有 recommendation_image 应该有任务代码,因为工作人员将处理这些任务:
推荐Dockerfile:
FROM python:2.7-wheezy
RUN pip install celery
COPY tasks_src_code..
WebDockerfile:
FROM python:2.7-wheezy
RUN pip install celery
RUN pip install bottle
COPY web_src_code..
其他图像(rabbitmq:3-management 和 library/redis 可从 docker hub 获得,它们会在您运行 docker-compose up 时自动拉取)。
现在是这样的:在您的网络服务器中,您可以通过字符串名称触发 celery 任务并通过任务 ID 提取结果(不共享代码)web_server.py:
import bottle
from celery import Celery
rabbit_path = 'amqp://guest:guest@rabbit:5672/vhost'
celeryapp = Celery('recommendation', broker=rabbit_path)
celeryapp.config_from_object('config.celeryconfig')
@app.route('/trigger_task', method='POST')
def trigger_task():
r = celeryapp.send_task('calculate_recommendations_task', args=(1, 2, 3))
return r.id
@app.route('/trigger_task_res', method='GET')
def trigger_task_res():
task_id = request.query['task_id']
result = celery.result.AsyncResult(task_id, app=celeryapp)
if result.ready():
return result.get()
return result.state
最后一个文件config.celeryconfig.py:
CELERY_ROUTES = {
'calculate_recommendations_task': {
'exchange': 'recommendation_worker',
'exchange_type': 'direct',
'routing_key': 'recommendation_worker'
}
}
CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'msgpack', 'yaml']