Celery简介
Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。它是一个专注于实时处理的任务队列,同时也支持任务调度。
我们用celery处理异步job的项目中积累了一些经验。在这里整理一下。
。
Broker
broker在中文文档翻译为中间人1。celery支持多种broker,
稳定支持的有Rabbimq和Redis,而Redis可能存在断电时丢消息,我们选择Rabbitmq。
import config
from celery import Celery
broker = "amqp://{user}:{password}@{host}:{port}/{vhost}".format(
user=config.get('AMQP', 'USER'),
password=config.get('AMQP', 'PASSWORD'),
host=config.get('AMQP', 'HOST'),
port=config.get('AMQP', 'PORT'),
vhost=config.get('AMQP', 'VHOST'))
celery_app = Worker('tasks',
broker=broker)
Backend
celery设计支持backend,用于存储这些消息以及celery执行的一些消息和结果。一般情况下我们选择Mysql作为backend。
backend = 'db+mysql://{user}:{password}@{host}:{port}/{db}'.format(
user=config.get('MYSQL', 'USER'),
password=config.get('MYSQL', 'PASSWORD'),
host=config.get('MYSQL', 'HOST'),
port=config.get('MYSQL', 'PORT'),
db=config.get('MYSQL', 'DATABASE'))
celery_app = Worker('tasks',
broker=broker,
backend=backend)
配置队列
celery可以配置多个Exchange,多个Queue。Exchange和Queue都是Rabbitmq中的概念。
myexchange = Exchange('myexchange', type='topic')
CELERY_QUEUES = (
Queue('defaultqueue', myexchange, routing_key="default.#"),
Queue('myqueue', myexchange, routing_key='my.#'),
Queue('testqueue', myexchange, routing_key='test.#')
)
例子中,用到一个exchange,topic类型,根据task的routing_key路由到多个queue。routing_key采用模式匹配,根据开头字段判断选择queue。如果exchange为direct类型,也能启动服务,但是routing_key里的#符号就不具备模式匹配特殊含义了。
CELERY_ROUTES还有另一种配置方式,只是由元组变成字典,实现的功能是类似的。
CELERY_QUEUES = {'myqueue': {'exchange': 'myexchange',
'routing_key': 'my.#'},
'testqueue': {'exchange': 'testexchange',
'routing_key': 'test.#'}}
路由
队列影响的是celery的consumer,consumer监听queue。路由影响producer,
CELERY_ROUTES = {'test.add': {'exchange': 'testexchange',
'routing_key': 'test.add'},
'test.del': {'exchange': 'testexchange',
'routing_key': 'test.add'},
}
producer会根据路由配置将消息发送到指定exchange,并设置routing_key。
错误重试
celery支持错误重试,可以设置重试次数,重试间隔等,非常方便。
class MyTask(Task):
max_retries = 3
default_retry_delay = 1
@celery_app.task(bind=True, name='test.del', base=MyTask)
def testdel(self, x, y):
try:
return True, x - y
except Exception as exc:
raise self.retry(exc=exc)