2

Python リサイクル サーバー TProcessPoolServer を正常にシャットダウンするにはどうすればよいですか? ドキュメント、例、ブログ投稿は見つかりませんでした。以下は、これまでの私の経験です。

スーパーバイザの下ではなく、コマンド ライン ./thrift_service.py で直接リサイクル サーバーを実行しています。私はpython 2.6とthrift 0.8.0を使用しています。

私は最初に試しました:

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

親の python プロセスに sigterm を送信すると、出力に「Terminated」と表示され、プロセスは強制終了されますが、その子は孤立して実行を続けます。

それから私は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 を親の python プロセスに送信すると、サーバーは接続の受け入れを停止しますが、プロセスは終了しません。

出力に次のように表示されます。

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()

これは予想されることですが、シグナルが再びキャッチされ、プロセスが開始状態ではなくなり、サーバーが停止するように求められます。この部分は約 10 回発生し、それ以上の出力はありません。

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
4

2 に答える 2

2

シグナルとそれが公開するpostForkCallbackを使用して、PythonのTProcessPoolServerに正常なシャットダウンを追加しました。TProcessPoolServerは、初期化されると、各ワーカープロセスでpostForkCallbackを呼び出します。これにより、シグナルハンドラーをセットアップし、正常にシャットダウンできます。ワーカーはSystemExitまたはKeyboardInterruptException例外のいずれかをキャッチするため、SIGINTのハンドラーをセットアップし、クリーンアップが終了したらsys.exit(0)を呼び出すと、ワーカーがシャットダウンします。

import signal
import sys

def setupHandlers():
    signal.signal(signal.SIGINT, handleSIGINT)
    #Optionally if you want to keep the current socket connection open and working
    #tell python to make system calls non-interruptable, which is probably what you want.
    signal.siginterrupt(signal.SIGINT, False)

def handleSIGINT(sig, frame):
     #clean up state or what ever is necessary
     sys.exit(0)

server = TProcessPoolServer(processor, transport, tfactory, pfactory)
server.setPostForkCallback(setupHandlers)

#Setup handlers in main process too
setupHandlers()

#Start server
server.start()

このようにして、生成されるすべてのワーカープロセスは、正常なシャットダウンを正しく処理するようにシグナルハンドラーを設定します。この例では、メインプロセスとユースケースに応じて機能する可能性のあるワーカーに同じハンドラーを設定しましたが、必要に応じてメインプロセスに別のハンドラーを簡単に定義できます。また、ハンドラーは各プロセスのコンテキストから呼び出されるため、クリーンアップ中にプロセス間で状態を共有できないことに注意してください。

signal.siginterruptの機能と、それが必要になる理由の詳細については、http: //docs.python.org/library/signal.htmlを参照してください。

編集:Crtl + Cを使用して、またはデーモンとして実行されている場合は、SIGINTシグナルをすべてのプロセスに送信する必要があります。kill-SIGINT[すべてのプロセスのpid]

ps --ppid [parent pid]を使用して、ワーカーのpidを簡単に取得できます。

于 2012-05-25T16:58:29.607 に答える