RuntimeError:永远不要在任务Celery中调用result.get()

时间:2017-08-03 17:15:05

标签: python django redis celery

我正在使用芹菜将任务发送到远程服务器并尝试将结果返回。使用远程服务器上的update_state方法不断更新任务状态。

我正在使用

发送任务
if Auth.auth().currentUser != nil {
    // User is signed in.
    // ...
} else {
    // No user is signed in.
    // ...
}

获取芹菜任务的结果是一个阻止调用,我不希望我的django应用程序等待结果和超时。

所以我尝试运行另一个芹菜任务来获得结果。

app.send_task('task_name')

但它会导致以下错误。

@app.task(ignore_result=True)
def catpure_res(task_id):
    task_obj = AsyncResult(task_id)
    task_obj.get(on_message=on_msg)

此错误是否有解决方法?我是否必须运行守护进程才能获得结果?

2 个答案:

答案 0 :(得分:8)

使用allow_join_result。请参阅下面的代码段。

@app.task(ignore_result=True)
def catpure_res(task_id):
    task_obj = AsyncResult(task_id)
    with allow_join_result():
        task_obj.get(on_message=on_msg)

注意:正如其他答案中所提到的那样,它可能会导致性能问题甚至死锁,但如果您的任务编写得很好并且不会导致意外错误,那么它应该像魅力一样工作。

答案 1 :(得分:2)

正如您的标题所解释的那样,在任务中调用get是一种不好的做法,可能导致死锁。 相反,您可以检查任务状态,并在其准备就绪时get结果:

result = catpure_res.AsyncResult(task_id, app=app)
    if result.ready():
        return result.get()

    return result.state

您可以将上述代码段包装在一个函数中,并每隔x秒请求一次。

编辑:关注您的评论:

  • 您可以改为使用result.state,并将retry机制与countdown一起使用,直到任务result.state == SUCCESS

  • 您可以添加celery beat来运行定期任务,检查主要任务是否结束。

  • 请注意,使用如此繁重的任务(持续时间很长)也是一种不好的做法。考虑将其分解为一个小任务并使用canvas来组合它们。