在 @inlineCallbacks-decorated 函数中未处理的异常不会触发 Errback
Errback not being fired on unhandled exception within @inlineCallbacks-decorated function
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。当它触发时,会抛出一个异常,我希望它会被与我的顶级 Deferred 对象关联的 errback 捕获:
foo()
被调用并立即 returns 延迟。我们向它添加一个 errback,它只打印出它的参数。
- 几秒钟后,反应器调用
fail()
。
fail()
抛出异常。
- 异常是 "thrown" 在生成器生成时进入生成器。 Documentation:
The generator will be sent the result of the Deferred with the 'send' method on generators, or if the result was a failure, 'throw'.
- 异常未在生成器中捕获,因此
foo()
的 Deferred 应该调用其 errback:
Your inlineCallbacks-enabled generator will return a Deferred object, which ... will fail with a failure object if your generator raises an unhandled exception
- 在调用errback时,应该调用
dump()
。
改为:
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) 工作正常,调用了我的 errback。
(b) 不起作用,并导致同样的问题:
@inlineCallbacks
def foo():
try:
yield reactor.callLater(5.0, fail)
except Exception, e:
print e
这是 Twisted 15.1.0 和 Python 2.7.10。
啊,reactor.callLater
没有 return Deferred。你可以让它与
一起工作
def fail(_):
raise Exception()
@inlineCallbacks
def foo():
d = Deferred()
d.addCallback(fail)
reactor.callLater(1.0, d.callback, None)
yield d
您也可以使用 deferLater
,因为这会 return 成为您想要的 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()
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。当它触发时,会抛出一个异常,我希望它会被与我的顶级 Deferred 对象关联的 errback 捕获:
foo()
被调用并立即 returns 延迟。我们向它添加一个 errback,它只打印出它的参数。- 几秒钟后,反应器调用
fail()
。 fail()
抛出异常。- 异常是 "thrown" 在生成器生成时进入生成器。 Documentation:
The generator will be sent the result of the Deferred with the 'send' method on generators, or if the result was a failure, 'throw'.
- 异常未在生成器中捕获,因此
foo()
的 Deferred 应该调用其 errback:
Your inlineCallbacks-enabled generator will return a Deferred object, which ... will fail with a failure object if your generator raises an unhandled exception
- 在调用errback时,应该调用
dump()
。
改为:
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) 工作正常,调用了我的 errback。
(b) 不起作用,并导致同样的问题:
@inlineCallbacks
def foo():
try:
yield reactor.callLater(5.0, fail)
except Exception, e:
print e
这是 Twisted 15.1.0 和 Python 2.7.10。
啊,reactor.callLater
没有 return Deferred。你可以让它与
def fail(_):
raise Exception()
@inlineCallbacks
def foo():
d = Deferred()
d.addCallback(fail)
reactor.callLater(1.0, d.callback, None)
yield d
您也可以使用 deferLater
,因为这会 return 成为您想要的 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()