如何捕获来自 reactor.stop() 的未处理错误
我刚接触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 个回答
4
问题在于,在你的 error
函数中,你返回了 result
,而这个 result
是一个 Failure
对象,因为它是通过错误回调调用的。返回一个 Failure
对象是重新引发错误状态的两个条件之一。以下是来自 krondo的twisted介绍 - 第9部分 的一段说明:
在同步代码中,我们可以使用没有任何参数的 raise 关键字“重新引发”一个异常。这样做会重新引发我们正在处理的原始异常,并允许我们在不完全处理错误的情况下对错误采取一些行动。实际上,我们在错误回调中也可以做到这一点。如果一个延迟(deferred)认为一个回调/错误回调失败,条件如下:
- 回调/错误回调引发了任何类型的异常,或者
- 回调/错误回调返回了一个 Failure 对象。
由于错误回调的第一个参数总是一个 Failure,因此错误回调可以通过返回它的第一个参数来“重新引发”异常,前提是它先执行了想要的操作。
没错,我刚试过,如果你把:
def error(results):
print 'error'
return results
改成
def error(results):
print 'error'
return
你就不会重新引发错误状态,这样它就不会传回反应器,也不会导致让你烦恼的追踪信息。
附言:我非常推荐 krondo的twisted介绍!虽然内容很长,但如果你能看完,你真的能在twisted中编写代码,这些行为就不会再是个谜了。
再附言:我看到你之前有一个SO问题 (Python DeferredList 回调在延迟引发错误时报告成功),这可能是你这样编写代码的原因。我觉得你可能对延迟(deferreds)中涉及的返回值/回调值(特别是错误回调)有根本性的误解。看看 第9部分(不过你可能需要回顾一下 第7部分 或更早的内容)来理清思路,这真的会帮助你澄清问题。