Как остановить TimerService из LoopingCall - PullRequest
0 голосов
/ 08 марта 2011

Фон

Недавно я участвовал в проекте, где использовался витой.Мы использовали TimerService для демонизации процесса.И да, я понимаю, что этот подход может был излишним, но мы пытаемся оставаться последовательными и использовать проверенные рамки.Вчера в LoopingCall возникла необработанная исключительная ситуация, которая привела к сбою TimerService, но приложение twistd все еще работало (см. запрос на улучшение витой информации ).Чтобы избежать этого, мы хотели бы остановить службу в конце обработчика исключений для всеобщего охвата.

Вопрос

Как остановить TimerService и Twistdприложение из вызываемого метода LoopingCall?Меня беспокоит то, что процесс linux продолжает работать, когда TimerService не может обработать исключение, даже если TimerService больше не выполняет цикл.

Например:


def some_callable():
  try:
    # do stuff
  except SomeSpecificError ex:
    # handle & log error
  except SomeOtherSpecificError ex:
    # handle & log error
  except:
    # log sys.exc_info() details
    # stop service.

ПРИМЕЧАНИЕ : в вызываемой функции не работает следующее.


from twisted.internet import reactor
reactor.stop()

1 Ответ

5 голосов
/ 08 марта 2011

Вы не можете остановить реактор до его запуска:

>>> from twisted.internet import reactor
>>> reactor.stop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/internet/base.py", line 570, in stop
    "Can't stop reactor that isn't running.")
twisted.internet.error.ReactorNotRunning: Can't stop reactor that isn't running.
>>> 

Однако, если реактор уже работает, reactor.stop работает нормально:

>>> from twisted.internet import reactor
>>> reactor.callLater(3, reactor.stop)
<twisted.internet.base.DelayedCall instance at 0xb762d2ec>
>>> reactor.run()
[... pause ...]
>>> 

TimerService - это обертка вокруг LoopingCall. А более конкретно, когда он начинает LoopingCall, он передает now=True в run. Это приводит к немедленному вызову функции в первый раз, а не после истечения указанного интервала один раз.

Итак, когда вызывается TimerService.startService, вызывается ваша функция. И реактор еще не работает. При первом вызове вашей функции вы не можете остановить реактор, потому что он еще не запущен.

Эта программа:

from twisted.application.internet import TimerService

def foo():
    from twisted.internet import reactor
    reactor.stop()

from twisted.application.service import Application

application = Application("timer stop")
TimerService(3, foo).setServiceParent(application)

дает такие результаты:

exarkun@boson:/tmp$ twistd -ny timerstop.tac
2011-03-08 11:46:19-0500 [-] Log opened.
2011-03-08 11:46:19-0500 [-] using set_wakeup_fd
2011-03-08 11:46:19-0500 [-] twistd 10.2.0+r30835 (/usr/bin/python 2.6.4) starting up.
2011-03-08 11:46:19-0500 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2011-03-08 11:46:19-0500 [-] Unhandled Error
        Traceback (most recent call last):
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/application/service.py", line 277, in startService
            service.startService()
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/application/internet.py", line 284, in startService
            self._loop.start(self.step, now=True).addErrback(self._failed)
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/internet/task.py", line 163, in start
            self()
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/internet/task.py", line 194, in __call__
            d = defer.maybeDeferred(self.f, *self.a, **self.kw)
        --- <exception caught here> ---
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/internet/defer.py", line 133, in maybeDeferred
            result = f(*args, **kw)
          File "timerstop.py", line 5, in foo
            reactor.stop()
          File "/home/exarkun/Projects/Twisted/branches/simplify-ssl-4905/twisted/internet/base.py", line 570, in stop
            "Can't stop reactor that isn't running.")
        twisted.internet.error.ReactorNotRunning: Can't stop reactor that isn't running.

Однако, этот работает нормально:

from twisted.application.internet import TimerService

counter = 0

def foo():
    global counter
    if counter == 1:
        from twisted.internet import reactor
        reactor.stop()
    else:
        counter += 1

from twisted.application.service import Application

application = Application("timer stop")
TimerService(3, foo).setServiceParent(application)

И чуть менее грубо, вот так:

from twisted.application.internet import TimerService

def foo():
    from twisted.internet import reactor
    reactor.callWhenRunning(reactor.stop)

from twisted.application.service import Application

application = Application("timer stop")
TimerService(3, foo).setServiceParent(application)
...