twisted: 检查一个 deferred 是否已经被调用
题
这就是我想要完成的。我正在远程调用服务器以获取信息,我想阻止以等待信息。我创建了一个返回 Deferred 的函数,这样当 RPC 带有回复时,就会调用 deferred。然后我有一个从 threads.blockingCallFromThread(reactor, deferredfunc, args)
线程调用的函数。
如果出现问题——例如,服务器宕机——那么呼叫将永远不会解除阻塞。在这些情况下,我更希望延迟的人例外。
我部分成功了。我有一个延迟的 onConnectionLost
,当连接丢失时它会关闭。我将阻塞调用函数修改为:
deferred = deferredfunc(args)
self.onConnectionLost.addCallback(lambda _: deferred.errback(
failure.Failure(Exception("connection lost while getting run"))))
result = threads.blockingCallFromThread(
reactor, lambda _: deferred, None)
return result
这工作正常。如果服务器宕机,则连接丢失,并触发 errback。但是,如果服务器没有宕机,一切都干净利落地关闭,onConnectionLost
仍然会被触发,并且这里的匿名回调会尝试触发 errback,从而引发 AlreadyCalled
异常。
有没有什么巧妙的方法来检查一个 deferred 是否已经被解雇了?我想避免将其包装在 try/except
块中,但如果这是唯一的方法,我总是可以诉诸于此。
解决方案
有办法,但你真的不应该这样做。触发 Deferred
的代码应该跟踪它是否在关联状态下触发了 Deferred
。真的,当你启动 Deferred
时,你应该忘记它,以便它可以被正确地收集垃圾;这样你就不必担心调用它两次,因为你不会再引用它了。
此外,看起来您从调用 deferredfunc
的同一线程调用 blockingCallFromThread
。不要那样做;返回 Deferreds
的函数最有可能调用反应器 API,并且这些 API不是线程安全的。事实上,Deferred
本身并不是线程安全的。这就是为什么它是 blocking
Call
FromThread
,而不是 blockOnThisDeferredFromThread
。你应该做 blockingCallFromThread(reactor, deferredfunc, args)
。
如果您真的想要 errback-if-it's-been-called-otherwise-do-nothing 行为,您可能需要 取消 Deferred。