我该如何设计一个扭曲的工厂以处理断开连接?
我在一个模块里有一个叫做ReconnectingClientFactory的东西。我希望这个模块尽可能灵活。我只需要一个TCP连接。我用这个工厂来持续管理这个连接。在过去,这个工厂在连接断开时会不停地尝试重新连接,但从来没有告诉上层脚本(也就是导入这个模块的脚本)连接出现了问题。
下面是我现在的一个简单例子:
Factory(protocol.ReconnectingClientFactory):
def clientConnectionFailed(self, connector, reason):
...
def clientConnectionLost(self, connector, reason):
...
我觉得最好是在连接出现问题时,通知上层脚本(导入模块的脚本)。这样,上层脚本可以自己定义如何处理断开连接的情况,而不是所有的处理逻辑都写死在模块里。但是,怎样才能把连接问题传达给上层脚本呢?
我可以抛出一个异常,但这个异常会在哪里被捕获呢?我想反应器(reactor)会捕获到,但这对我有什么帮助呢?
我没有可以用来通知上层脚本连接问题的回调函数或错误回调。
上层脚本可以提供一些特定的函数作为参数,当连接出现问题时调用这些函数。这样设计好吗?
1 个回答
这个问题有点抽象,没法直接回答。具体要看你的顶层模块在做什么。
不过,你应该考虑使用端点,而不是ClientFactory
。这样可能会解决你一些设计上的疑问。接收连接丢失的通知会有点麻烦(因为ClientFactory.clientConnectionLost
其实是IProtocol.connectionLost
的重复通知,在端点API中已经没有了;所以如果你在意这个,就得把IProtocol
对象包裹起来),但这让你可以使用更通用的机制来重试失败的连接。比如,原本你会收到clientConnectionFailed
的通知,现在你只需在从connect
得到的Deferred
上处理错误回调就行了。因此,如果你只是想“不断重连直到成功”,你可以使用这个完全通用的Deferred
重试循环,而不是像ReconnectingClientFactory
那样特定于连接的东西:
# Warning, untested, sorry if it's broken.
@inlineCallbacks
def retry(deferredThing, delay=30.0, retryCount=5):
retries = retryCount
while True:
try:
result = yield deferredThing()
except:
if not retries:
raise
retries -= 1
log.err()
yield deferLater(reactor, delay, lambda : None)
else:
returnValue(result)
同样,如果你能让那个deferredThing
函数返回一个Deferred
,只有在你的协议应用逻辑完成时才会触发,除了调用IStreamServerEndpoint.connect
,还要监控connectionLost
,如果在有趣的逻辑完成之前连接丢失就会失败。
Deferreds
可以有效地管理这种跨多个系统层级的异步重试状态。