Python TProcessPoolServer是否正常关闭?
如何优雅地关闭python thrift服务器,TProcessPoolServer?我还没有找到任何文档、示例或博客帖子。以下是我到目前为止的经历 我直接在命令行/thrift_service.py上运行我的thrift服务器,而不是在主管的指导下运行。我使用的是python 2.6和thrift 0.8.0 我最初尝试: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.
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
}