витая: проверить, был ли вызван отложенный - PullRequest
2 голосов
/ 26 июля 2010

Это то, что я пытаюсь сделать.Я делаю удаленный вызов на сервер для информации, и я хочу заблокировать, чтобы ждать информацию.Я создал функцию, которая возвращает 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

Это прекрасно работает.Если сервер выходит из строя, соединение теряется, и запускается ошибка.Тем не менее, если сервер не выходит из строя и все отключается чисто, onConnectionLost по-прежнему срабатывает, и анонимный обратный вызов здесь пытается вызвать ошибку, вызывая исключение AlreadyCalled.

IsЕсть какой-нибудь аккуратный способ проверить, что отсроченный уже запущен?Я хочу не включать его в блок try/except, но всегда могу прибегнуть к этому, если это единственный способ.

1 Ответ

4 голосов
/ 26 июля 2010

Есть способы, но вы действительно не должны этого делать.Ваш код, который запускает Deferred, должен отслеживать, запущен ли Deferred или нет в связанном состоянии.Действительно, когда вы запускаете Deferred, вы должны потерять его, чтобы он мог правильно собирать мусор;таким образом, вам больше не нужно беспокоиться о его повторном вызове, поскольку у вас больше не будет ссылки на него.

Кроме того, похоже, что вы звоните deferredfunc из того же потока, что и вы.повторный звонок blockingCallFromThread.Не делай этого;функции, которые возвращают Deferreds, скорее всего, вызывают API реактора, и эти API не безопасны для потоков .На самом деле, Deferred сам по себе не является потокобезопасным.Вот почему это blockingCallFromThread, а не blockOnThisDeferredFromThread.Вы должны сделать blockingCallFromThread(reactor, deferredfunc, args).

Если вы действительно хотите, чтобы поведение «errback-if-it-was-вызвано-иначе-ничего», вы можете отменить Deferred.*

...