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()