我该如何设计一个扭曲的工厂以处理断开连接?

5 投票
1 回答
1490 浏览
提问于 2025-04-16 14:30

我在一个模块里有一个叫做ReconnectingClientFactory的东西。我希望这个模块尽可能灵活。我只需要一个TCP连接。我用这个工厂来持续管理这个连接。在过去,这个工厂在连接断开时会不停地尝试重新连接,但从来没有告诉上层脚本(也就是导入这个模块的脚本)连接出现了问题。

下面是我现在的一个简单例子:

Factory(protocol.ReconnectingClientFactory):

    def clientConnectionFailed(self, connector, reason):
        ...

    def clientConnectionLost(self, connector, reason):
        ...

我觉得最好是在连接出现问题时,通知上层脚本(导入模块的脚本)。这样,上层脚本可以自己定义如何处理断开连接的情况,而不是所有的处理逻辑都写死在模块里。但是,怎样才能把连接问题传达给上层脚本呢?

我可以抛出一个异常,但这个异常会在哪里被捕获呢?我想反应器(reactor)会捕获到,但这对我有什么帮助呢?

我没有可以用来通知上层脚本连接问题的回调函数或错误回调。

上层脚本可以提供一些特定的函数作为参数,当连接出现问题时调用这些函数。这样设计好吗?

1 个回答

3

这个问题有点抽象,没法直接回答。具体要看你的顶层模块在做什么。

不过,你应该考虑使用端点,而不是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可以有效地管理这种跨多个系统层级的异步重试状态。

撰写回答