如何捕获源自reactor.stop()的Deferred中的未处理错误

时间:2014-05-03 23:36:39

标签: python asynchronous twisted

我是新来的扭曲并且遇到以下脚本的问题。

当我运行以下内容时:

#!/usr/bin/env python
from twisted.internet import defer
from twisted.web.client import getPage, reactor

def success(results):
  print 'success'

def error(results):
  print 'error'
  return results

def finished(results):
  print 'finished'
  reactor.stop()

tasks = []

d = getPage('thiswontwork').addCallback(success).addErrback(error)
tasks.append(d)

dl = defer.DeferredList(tasks)
dl.addCallback(finished)

reactor.run()

我得到以下输出:

error
finished
Unhandled error in Deferred:
Unhandled Error
Traceback (most recent call last):
Failure: twisted.internet.error.ConnectionRefusedError: Connection was refused by other side: 61: Connection refused.

我的问题是,当我似乎在错误回调中发现错误时,为什么会出现未处理的错误?

1 个答案:

答案 0 :(得分:4)

问题在于,在error def中,您返回result,如果它被错误调用,则返回Failure个对象,并返回Failure个对象是重新提高错误状态的两个标准之一。请参阅krondo's twisted intro - part 9中的以下简介:

  

现在,在同步代码中,我们可以使用raise关键字“重新引发”异常,而不使用任何参数。这样做会引发我们正在处理的原始异常,并允许我们对错误采取一些操作而不完全处理它。事实证明我们可以在错误中做同样的事情。如果出现以下情况,延迟将认为回调/错误失败:

     
      
  • 回调/错误引发任何类型的异常,或
  •   
  • callback / errback返回一个Failure对象。
  •   
     

由于errback的第一个参数始终是Failure,因此errback可以在执行它想要执行的任何操作后通过返回其第一个参数来“重新引发”异常。

是的,如果你改变的话,试试吧:

def error(results):
  print 'error'
  return results

def error(results):
  print 'error'
  return

你不会再次提高错误状态,所以它不会渗透到反应堆中,并且不会导致让你烦恼的追溯。

P.S。我不能推荐krondo's twisted introduction!它可能真的很长,但如果你能够通过它,你真的能够生成扭曲的代码,这些行为不会成为一个谜。

P.P.S我看到你之前有关于延迟的SO问题(Python DeferredList callback reporting success when deferreds raise error),这可能就是你用这种方式构建代码的原因。我认为你可能对defs中涉及的def(特别是errbacks)的返回值/回调值有一个根本的误解。查看part 9(尽管您可能需要备份part 7或甚至更早来跟踪它)krondo,但它确实应该有助于清理。