三种启动任务的方式
apply_async(args[, kwargs[, …]])
启动一个task
delay(*args, **kwargs)
启动一个task的快捷方式,不支持选项
calling (call)
不会发送到工作进程 而是在当前进程执行
T.delay(arg, kwarg=value)
T.apply_async((arg,), {'kwarg': value})
T.apply_async(countdown=10)
T.apply_async(eta=now + timedelta(seconds=10))
T.apply_async(countdown=60, expires=120)
T.apply_async(expires=now + timedelta(days=2))
例子:
task.delay(arg1, arg2, kwarg1='x', kwarg2='y')
task.apply_async(args=[arg1, arg2], kwargs={'kwarg1': 'x', 'kwarg2': 'y'})
所以delay是清晰且方便的,但是如果想要加选项必须得apply_async。
另外如果任务不是在当前进程注册的,可以使用send_task来使用task名字来调用
linking
可以把两个任务连接起来
add.apply_async((2, 2), link=add.s(16))
这样把第一个任务的结果 4 发送到下一个任务,当然了,这种用法可以被视为是内部方法,应该考虑使用工作流的chain。
可以连接一个异常处理任务
使用errback处理task抛出异常的情况,
@app.task
def error_handler(uuid):
result = AsyncResult(uuid)
exc = result.get(propagate=False)
print('Task {0} raised exception: {1!r}\n{2!r}'.format(uuid, exc, result.traceback))
add.apply_async((2, 2), link_error=error_handler.s())
add.apply_async((2, 2), link=[add.s(16), other_task.s()])
指定在一定时间后运行
result = add.apply_async((2, 2), countdown=3)
tomorrow = datetime.utcnow() + timedelta(days=1)
add.apply_async((2, 2), eta=tomorrow)
但是并不保证说任务一定会在指定时间运行,可能在消息队列中的消息过多或网络阻塞导致不能在确切的时间运行。可以使用Munin来监视队列。
过期
add.apply_async((10, 10), expires=60)
add.apply_async((10, 10), kwargs, expires=datetime.now() + timedelta(days=1)
当工作进程收到了过期的任务,它会标记该任务为[REVOKED]
消息发送重试
celery会自动重发,可以设置该行为:
add.apply_async((2, 2), retry=False) # 禁用
策略
max_retries
最大尝试次数,默认为3次,可设为None表示一直重试。
interval_start
重试之间的时间间隔,默认为0即立即重试
interval_step
每次重试的时间间隔的增长步长,默认为0.2.
interval_max
重试之间的时间间隔最大数,默认为0.2.
add.apply_async((2, 2), retry=True, retry_policy={
'max_retries': 3,
'interval_start': 0,
'interval_step': 0.2,
'interval_max': 0.2,
})
Connection Error Handling
如果连接错误则会抛出OperationalError(启用了重试则会在重试次数耗尽之后再抛出)
Serializers
默认的序列化器是json,另可支持pickle、YAML、msgpack,可使用task_serializer在全局、任务甚至每个消息层级进行设置。
add.apply_async((10, 10), serializer='json')
压缩
可用的压缩格式:gzip,bzip2
add.apply_async((2, 2), compression='zlib')
连接
自从2.5 celery默认启用了连接池。
自行管理连接
results = []
with add.app.pool.acquire(block=True) as connection:
with add.get_publisher(connection) as publisher:
try:
for args in numbers:
res = add.apply_async((2, 2), publisher=publisher)
results.append(res)
print([res.get() for res in results])
Routing
# 指定该任务到该队列
add.apply_async(queue='priority.high')
当然了这种方式不推荐,应该使用task_routes配置
# 分配该worker到该队列
celery -A proj worker -l info -Q celery,priority.high
高级配置
exchange
routing_key
priority