Python TProcessPoolServer是否正常关闭?

Python TProcessPoolServer是否正常关闭?,python,thrift,Python,Thrift,如何优雅地关闭python thrift服务器,TProcessPoolServer?我还没有找到任何文档、示例或博客帖子。以下是我到目前为止的经历 我直接在命令行/thrift_service.py上运行我的thrift服务器,而不是在主管的指导下运行。我使用的是python 2.6和thrift 0.8.0 我最初尝试: server = TProcessPoolServer(processor, transport, tfactory, pfactory) try: server.

如何优雅地关闭python thrift服务器,TProcessPoolServer?我还没有找到任何文档、示例或博客帖子。以下是我到目前为止的经历

我直接在命令行/thrift_service.py上运行我的thrift服务器,而不是在主管的指导下运行。我使用的是python 2.6和thrift 0.8.0

我最初尝试:

server = TProcessPoolServer(processor, transport, tfactory, pfactory)
try:
    server.serve()
finally:
    server.stop()
当我向父python进程发送sigterm时,我在输出中看到“Terminated”,进程被终止,但其子进程被孤立并继续运行

然后我无意中发现了这条路,并尝试:

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

我已经使用信号和它公开的postForkCallback在python中为TProcessPoolServer添加了一个优雅的关闭。TProcessPoolServer初始化后将在每个工作进程中调用postForkCallback。这允许您设置信号处理程序并正常关机。由于worker捕获了SystemExit或KeyboardInterruptException异常,因此您可以为SIGINT设置一个处理程序,然后在完成清理后调用sys.exit(0),这将导致worker关闭

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的作用以及您可能需要它的原因的更多详细信息,请参阅

编辑:您需要使用Crtl+C向所有进程发送SIGINT信号,或者如果它作为守护进程kill-SIGINT[pids of all process]运行


您可以使用ps--ppid[parent pid]

轻松获得工人的pid程序启动后,我记录了主进程的进程号。然后根据
ps--ppid
,取回主进程的子进程并逐个杀死它们

我的服务的控件外壳脚本的代码:

function stop
{
    SERVER_PID=`cat logs/server.pid`
    SPIDS=`ps --ppid $SERVER_PID | awk '{if ($1!="PID") print $1}'`
    kill -9 $SERVER_PID
    for PID in $SPIDS
    do
        kill -9 $PID
    done
}
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
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()
function stop
{
    SERVER_PID=`cat logs/server.pid`
    SPIDS=`ps --ppid $SERVER_PID | awk '{if ($1!="PID") print $1}'`
    kill -9 $SERVER_PID
    for PID in $SPIDS
    do
        kill -9 $PID
    done
}