Errback没有在@inlineCallbacks-decorated函数内的未处理异常上触发

时间:2016-03-16 17:10:22

标签: python twisted

from twisted.internet import reactor
from twisted.internet.defer import inlineCallbacks


def fail():
  raise Exception()

@inlineCallbacks
def foo():
  yield reactor.callLater(5.0, fail)

def dump(*args, **kwargs):
  print 'dump', args, kwargs

d = foo()
d.addErrback(dump)

reactor.run()

这里我们有一个虚函数foo(),它产生一个将在5秒内触发的延迟函数。当它触发时,抛出一个异常,我期望它会被与我的顶级Deferred对象相关联的错误捕获:

    调用
  1. foo()并立即返回延迟。我们为它添加一个errback,它只打印出它的参数。
  2. 几秒钟后,反应堆呼叫fail()
  3. fail()抛出异常。
  4. 例外情况是"抛出"它产生的点进入发电机。 Documentation
  5.   

    生成器将通过发送'发送延迟的结果。关于生成器的方法,或者如果结果是失败的话,抛出'。

    1. 异常没有在生成器中捕获,因此foo()的Deferred应该调用它的errback:
    2.   

      你的inlineCallbacks启用的生成器将返回一个Deferred对象,如果你的生成器引发了一个未处理的异常,它将失败并显示失败对象

      1. 在调用errback时,应调用dump()
      2. 相反:

        Unhandled Error
        Traceback (most recent call last):
          File "untitled", line 19, in <module>
            reactor.run()
          File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 1192, in run
            self.mainLoop()
          File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 1201, in mainLoop
            self.runUntilCurrent()
        --- <exception caught here> ---
          File "/Library/Python/2.7/site-packages/twisted/internet/base.py", line 824, in runUntilCurrent
            call.func(*call.args, **call.kw)
          File "untitled", line 6, in fail
            raise Exception()
        exceptions.Exception:
        

        为了进一步测试,我尝试(a)直接在foo()内引发异常,并(b)尝试捕获fail()foo()引发的异常。

        (a)工作正常,我的错误被召回。

        (b)不起作用,导致同样的问题:

        @inlineCallbacks
        def foo():
          try:
            yield reactor.callLater(5.0, fail)
          except Exception, e:
            print e 
        

        这是Twisted 15.1.0和Python 2.7.10。

2 个答案:

答案 0 :(得分:1)

你也可以使用deferLater,因为这会像你想要的那样返回Deferred

from twisted.internet import task, defer, reactor

def fail(*args):
    raise Exception()

def error(*args):
    print(args)

def dump(*args, **kwargs):
    print('dump', args, kwargs)

@defer.inlineCallbacks
def foo():
    d = task.deferLater(reactor, 1.0, fail)
    d.addErrback(error)
    yield d

D = foo()
D.addCallback(dump)
reactor.run()

答案 1 :(得分:0)

啊,reactor.callLater没有返回延期。您可以使用

来实现此目的
def fail(_):
  raise Exception()

@inlineCallbacks
def foo():
  d = Deferred()
  d.addCallback(fail)
  reactor.callLater(1.0, d.callback, None)
  yield d