Как мне спроектировать скрученную фабрику для обработки разъединений? - PullRequest
5 голосов
/ 27 марта 2011

У меня есть ReconnectingClientFactory в модуле.Я бы хотел, чтобы модуль был максимально гибким.Мне нужно только одно соединение TCP.Я использую фабрику как постоянный интерфейс для этого соединения.В прошлом фабрика реагировала на отключения, бесконечно повторяя попытку подключения, никогда не сообщая сценарию верхнего уровня (сценарию, который импортирует модуль), что были проблемы с подключением.

Вот краткий пример того, что у меня есть:

Factory(protocol.ReconnectingClientFactory):

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

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

Я думаю, что будет лучше, если я сообщу скрипту верхнего уровня (скрипту, который импортирует модуль), когда возникнут проблемы с соединением.Таким образом, скрипт верхнего уровня может определять поведение разрешения разрыва, а не все это жестко задано в модуле.Но каков наилучший способ сообщить о проблемах соединения скрипту верхнего уровня?

Я мог бы вызвать исключение, но где бы оно могло быть поймано?Я предполагаю, что реактор поймает его, но как это поможет?

Нет обратных вызовов или ошибок, которые я могу запустить, чтобы сообщить верхнему сценарию о проблеме соединения.

Верхний сценарий может предоставитьспецифические функции [в качестве аргументов], вызываемые при возникновении проблем с соединением.Это хороший дизайн?

1 Ответ

3 голосов
/ 27 марта 2011

Этот вопрос слишком абстрактен, чтобы дать прямой ответ. Это зависит от того, что делает ваш модуль верхнего уровня.

Однако вам следует рассмотреть возможность использования конечных точек , а не ClientFactory. Это может решить некоторые ваши вопросы дизайна. Получение уведомлений о потере соединения немного сложнее (поскольку ClientFactory.clientConnectionLost на самом деле является дублирующим уведомлением IProtocol.connectionLost, его больше нет в API конечных точек; поэтому вам нужно обернуть объект IProtocol, если вам это нужно), но это позволяет использовать более общие механизмы для повторения неудачных соединений, поскольку вместо clientConnectionFailed вы просто получаете ошибку на Deferred, которую вы вернули с connect. Так, например, если все, что вы хотели сделать, это «продолжать повторное подключение до тех пор, пока вы не добьетесь успеха», вы можете использовать этот совершенно общий Deferred -retry-loop вместо чего-то определенного для соединений, таких как 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 может быть эффективным способом управления этим типом асинхронного повторного попытки на нескольких уровнях системы.

...