[英]Celery redis backend not always returning result
我正在经营芹菜工人,以便:
-------------- celery@ v3.1.23 (Cipater)
---- **** -----
--- * *** * -- Linux-4.4.0-31-generic-x86_64-with-debian-stretch-sid
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: __main__:0x7fe76cd42400
- ** ---------- .> transport: amqp://
- ** ---------- .> results: redis://
- *** --- * --- .> concurrency: 4 (prefork)
-- ******* ----
--- ***** ----- [queues]
-------------- .> celery exchange=celery(direct) key=celery
[tasks]
. tasks.mytask
tasks.py :
@celery_app.task(bind=True, ignore_result=False)
def mytask(task):
r = redis.StrictRedis()
r.rpush('/task_finished', task.request.id)
return {'result': 42}
当我尝试运行以下代码,并且一个接一个地运行2个任务时,它在获取第一个结果但未能返回第二个结果时起作用。
import celery.result
import redis
r = redis.StrictRedis()
celery_app = Celery(name="my_long_task", backend="redis://")
while True:
_, resp = r.blpop('/task_finished')
task_id = resp.decode('utf-8')
task = celery.result.AsyncResult(task_id, app=celery_app)
print(task)
print(task.result)
将返回:
第一循环 :
[1] 990e2d04-5664-4d7c-8a5c-e9cb4ef45e24
[2] {'result': 42}
第二个循环 (无法返回结果):
[3] 8463cc46-0884-4bf7-b838-f0614f74b271
[4] {}
但是如果我在while
循环中实例化celery_app = Celery(name="my_long_task", backend="redis://")
,它每次都会工作。
没有重新celery_app
什么问题? 我错过了什么?
编辑:
等待结果(在延迟的情况下)也不会起作用
while True:
_, resp = r.blpop('/task_finished')
task_id = resp.decode('utf-8')
for i in range(0, 20):
# Won't work because I need to re instantiate celery_app
task = celery.result.AsyncResult(task_id, app=celery_app)
print(task.result)
time.sleep(1)
你有竞争条件。 这是发生的事情:
循环到达_, resp = r.blpop('/task_finished')
并在那里阻塞。
该任务执行r.rpush('/task_finished', task.request.id)
循环解除task = celery.result.AsyncResult(task_id, app=celery_app)
,执行task = celery.result.AsyncResult(task_id, app=celery_app)
并获得一个空结果,因为该任务尚未将其结果记录到数据库中。
在芹菜将结果提交给后端后 , r.rpush
可能有一种方法。 也许创建一个派生自Task
的自定义类就可以了。 但这不是我尝试过的。
但是,您当然可以修改代码以将结果与任务ID 一起存储。 就像是:
r.rpush('/task_finished', json.dumps({ "task_id": task.request.id, "result": 42 }))
为了说明,我使用了JSON序列化。 你可以使用你想要的任何方案。 阅读时:
_, resp = r.blpop('/task_finished')
resp = json.loads(resp)
有了这个,您可能希望将ignore_result=False
更改为ignore_result=True
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.