Python 如何阻止链中的失败任务的链执行?
问题Python 如何阻止链中的失败任务的链执行?,python,task,celery,chain,Python,Task,Celery,Chain,问题 如何停止链中某个任务失败的链执行? 示例 @app.task def ok(i): 打印(f“ok={i}”) 返回i+1 @应用程序任务 def失败(i): 打印(f“fail={i}”) 引发运行时错误(str(i)) 如果名称=“\uuuuu main\uuuuuuuu”: 中间的失败=(ok.s(1)| fail.s()| ok.s()) 在_end=(ok.s(1)| fail.s())中失败 对于c in[末端失败,中间失败]: resp=c.延迟() 尝试: 响应获取(超时=
如何停止链中某个任务失败的链执行?
示例@app.task
def ok(i):
打印(f“ok={i}”)
返回i+1
@应用程序任务
def失败(i):
打印(f“fail={i}”)
引发运行时错误(str(i))
如果名称=“\uuuuu main\uuuuuuuu”:
中间的失败=(ok.s(1)| fail.s()| ok.s())
在_end=(ok.s(1)| fail.s())中失败
对于c in[末端失败,中间失败]:
resp=c.延迟()
尝试:
响应获取(超时=5)
除运行时错误外:
打印(“运行时错误(按预期)”)
芹菜除外。时间错误:
#问:我怎样才能让“中间失败”永远不会发生?
打印(“超时(非预期)”)
观察结果
- 中间链中的
失败:
总是导致resp.get(timeout=2)
李>TimeoutError
:始终引发在\u端失败\u
,并且不等待超时运行时错误(2)
AsyncResult.get()
将永远阻止,但是通过设置self.request.chain=None来清理链没有帮助,链仍然被阻止,直到达到超时
当Redis同时用作消息代理和结果存储时,就会出现上述行为。当任务标记为“急切”(在当前流程中执行)时,行为与预期一致
如有任何见解,我将不胜感激。谢谢大家! 拿到了,希望它能帮助别人。所有学分都归Ing所有。约苏埃·巴兰德拉诺·科罗内尔
当你以这样的方式得到结果时,有一个警告。
链是一组链接在一起的任务,当您执行resp=c.delay()
时,您将对链中的所有任务进行排队
c.delay()
返回的对象不是指向整个链的指针,而是指向链中最后一个任务的指针。
这意味着,resp
以指向链中最后一个任务的结果的指针结束,在本例中是第二个ok.s()
。
这意味着如果中间任务失败,并且您尝试执行resp.get()
它将超时,因为resp
指向的任务从未实际执行过
这也解释了您在\u端看到的失败的行为,因为resp
是指向fail.s()
的指针,当您执行resp.get()
芹菜将引发任务中发生的错误。这就是芹菜如何处理引起错误的任务的访问结果,并且任务中没有错误处理
现在,根据你真正想做的事情,你可以做一些不同的选择。按推荐顺序
1) 您可以向链中添加成功和错误处理程序,以确保您没有使用不完整的链
2) 使用resp.collect(intermediate=True)
collect()
以有向无环图(DAG)的形式返回链中的所有结果。通常更容易将其转换为列表,以便您可以按顺序循环查看每个结果:
3) 向后走链图,直到到达父对象并循环遍历子对象以获得结果。
由于您在resp
中得到的结果实际上是链中的最后一个任务,因此您可以向后遍历图形,直到链中的第一个任务,并从中获得结果:
也许你碰到了一只虫子?你试过芹菜问题吗?是的,我正在github上探讨芹菜问题,有很多类似的问题,但不是完全相同的问题。我发现的大多数问题都与错误处理程序无关。这些解决方案中没有一个能让我在中间发现失败吗?result.get()永远挂起在中间收集循环中。while results.ready():循环也是如此。你有没有机会分享一个完整的工作示例,包括你是如何实际获得失败结果的?没关系,我发现了问题。这是因为我使用的是rpc://芹菜后端,这些链似乎有很多问题。我切换到amqp://它现在工作得很好。
@app.task(bind=True)
def success(self, result):
print(f"Chain result: ${result}")
print(f"Chain: ${self.chain}")
@app.task(bind=True)
def error(self, *args, **kwargs)
print(f"args: ${args)")
print(f"kwargs: ${kwargs}")
if __name__ == "__main__":
fails_in_the_middle = (ok.s(1) | fail.s() | ok.s() | success.s()).on_error(error.s())
fails_in_the_end = (ok.s(1) | fail.s() | success.s()).on_error(error.s())
resp = c.delay()
for result in list(resp.collect(intermediate=True)):
print(result.get())
resp = c.delay()
parent = resp.parent
while parent is not None:
parent = resp.parent
for child in parent.children:
child.get()