2012-05-21 2 views
2

Как вы изящно завершите работу python бережливого сервера TProcessPoolServer? Я не нашел никаких документов, примеров или сообщений в блогах. Дальше мой опыт, до сих пор.TProcessPoolServer грациозное завершение работы?

Я запускаю свой бережливый сервер непосредственно в командной строке ./thrift_service.py, а не под наблюдением. Я использую python 2.6 и бережливость 0.8.0.

Первоначально я попробовал:

server = TProcessPoolServer(processor, transport, tfactory, pfactory) 
try: 
    server.serve() 
finally: 
    server.stop() 

Когда я посылаю SIGTERM процесс питона родительского, я вижу «Отменен» в выводе, что процесс был убит, а его дети осиротели и продолжают работать.

Потом я наткнулся на thrift server tests, и попробовал:

import signal 
def set_alarm(server): 
    def clean_shutdown(signum, frame): 
     for worker in server.workers: 
      logging.error("Terminating worker: {0}".format(worker)) 
      worker.terminate() 
     logging.error("Requesting server to stop()") 
     try: 
      server.stop() 
     except (KeyboardInterrupt, SystemExit): 
      pass 
     except Exception as err: 
      logging.exception(err) 
    def logme(s, *args, **kwargs): 
     logging.error(">>> {0} <<<".format(s)) 
     clean_shutdown(*args, **kwargs) 
    signal.signal(signal.SIGALRM, clean_shutdown) 
    signal.signal(signal.SIGHUP, clean_shutdown) 
    signal.signal(signal.SIGINT, clean_shutdown) 
    signal.signal(signal.SIGTERM, lambda x, y: logme("SIGTERM", x, y)) 
server = TProcessPoolServer(processor, transport, tfactory, pfactory) 
set_alarm(server) 
server.serve() 

и когда я отправить SIGTERM, SIGALRM, SIGHUP, или SIGINT к процессу питона родительского, сервер перестает принимать соединения, но процессы не являются прекращается.

В выходе я вижу:

ERROR:root:>>> SIGTERM <<< 
ERROR:root:Terminating worker: <Process(Process-1, started daemon)> 
ERROR:root:Terminating worker: <Process(Process-2, started daemon)> 
ERROR:root:Terminating worker: <Process(Process-3, started daemon)> 
ERROR:root:Terminating worker: <Process(Process-4, started daemon)> 
ERROR:root:Terminating worker: <Process(Process-5, started daemon)> 
ERROR:root:Requesting server to stop() 

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

ERROR:root:>>> SIGTERM <<< 
ERROR:root:Terminating worker: <Process(Process-1, unknown daemon)> 
ERROR:root:Requesting server to stop() 

А иногда я вижу AssertionError внутри многопроцессорной библиотеки:

Traceback (most recent call last): 
    File "/path/to/thrift_service.py", line 340, in clean_shutdown 
    server.stop() 
    File "/usr/local/lib/python2.6/dist-packages/thrift/server/TProcessPoolServer.py", line 123, in stop 
    self.stopCondition.notify() 
    File "/usr/lib/python2.6/multiprocessing/synchronize.py", line 223, in notify 
    assert not self._wait_semaphore.acquire(False) 
AssertionError 

ответ

2

Я добавил корректное завершение к TProcessPoolServer в Python с использованием сигналов и postForkCallback, что она обнажает. TProcessPoolServer будет вызывать ваш postForkCallback в каждом рабочем процессе после его инициализации. Это позволяет вам грамотно настраивать обработчики сигналов и выключение. Поскольку рабочие ловит исключения SystemExit или KeyboardInterruptException, вы можете настроить обработчик для SIGINT, а затем, как только вы закончите очистку вызова sys.exit (0), и это приведет к отключению рабочего.

Таким образом, каждый рабочий процесс, который порожден, устанавливает обработчики сигналов, чтобы правильно обрабатывать грациозное завершение работы. В этом примере я устанавливаю тот же обработчик для основного процесса, а также для рабочих, которые могут работать в зависимости от используемого вами случая, но вы можете легко определить другой обработчик для основного процесса, если вам нужно. И помните, что обработчик будет вызван из контекста каждого процесса, поэтому вы не сможете делиться состоянием через процесс во время очистки.

см. http://docs.python.org/library/signal.html для получения более подробной информации о том, какой сигнал.сигнализирует и почему он вам может понадобиться.

Edit: Вам нужно будет посылать сигнал SIGINT всего процесса с помощью Ctrl + C или, если он работает в качестве демона убить -SIGINT [ИДП всех процессов]

Вы можете получить ИКИ рабочие легко используют ps -ppid [родительский pid]

Смежные вопросы