2014-01-15 50 views
2

我有更多的代码比这个,所以我正在修剪它似乎是相关的。每所记录的例子,我有ZeroRPC使用Python类:ZeroRPC python服务器异常,当试图停止或关闭

import zerorpc, sys, signal 

class MyClass: 
    pass 

zpc = 0 
if __name == '__main__': 
    zpc = zerorpc.Server(MyClass) 
    zpc.bind('ipc://./mysocket.sock') 
    zpc.run() 
    print("zpc stopped"); sys.stdout.flush() 

的Python脚本是催生了从我的Node.js服务器子进程监听到标准输出和标准错误。当客户端连接超时或服务器关闭时,我在发送SIGTERM的ChildProcess上调用kill()。

仅仅使用上面的代码,'zpc stopped'永远不会被Node.js回调捕获,这向我表明ZeroRPC服务器在其运行循环中的某处被杀死。此外,套接字文件仍然存在,指示服务器也不关闭套接字。

Gateway Error: File "/usr/lib/python2.6/site-packages/zerorpc/core.py", line 178, in stop 

Gateway Error:  self._acceptor_task.kill() 
    File "/usr/lib64/python2.6/site-packages/gevent/greenlet.py", line 235, in kill 

Gateway Error:  waiter.get() 
    File "/usr/lib64/python2.6/site-packages/gevent/hub.py", line 568, in get 

Gateway Error:  return self.hub.switch() 
    File "/usr/lib64/python2.6/site-packages/gevent/hub.py", line 330, in switch 
    switch_out() 
    File "/usr/lib64/python2.6/site-packages/gevent/hub.py", line 334, in switch_out 
    raise AssertionError('Impossible to call blocking function in the event loop callback') 
AssertionError: Impossible to call blocking function in the event loop callback 

Gateway Error: Traceback (most recent call last): 
    File "gateway.py", line 111, in <module> 
    zpc.run() 

Gateway Error: File "/usr/lib/python2.6/site-packages/zerorpc/core.py", line 171, in run 
    self._acceptor_task.get() 
    File "/usr/lib64/python2.6/site-packages/gevent/greenlet.py", line 258, in get 

Gateway Error:  result = self.parent.switch() 
    File "/usr/lib64/python2.6/site-packages/gevent/hub.py", line 331, in switch 

Gateway Error:  return greenlet.switch(self) 
AssertionError: Impossible to call blocking function in the event loop callback 

更改站:

def sig_handle (signal, frame): 
    global zpc 
    print("SIGTERM received.") # <-- this does occur 
    zpc.stop() # <-- Exception thrown here and at run() 
    sys.exit(0) 

signal.signal(signal.SIGTERM, sig_handle) 

例外的是通过它的标准错误回调拾起的Node.js:所以我想我会捕捉SIGTERM后调用服务器上的stop()或close() ()关闭()会导致相同的最终异常集合。在Javascript(Node.js)中实现相同的想法,close()清除正在运行的服务器(及其在目录中的套接字文件),而不会引发任何异常或警告。

这一切都给我留下了一个问题:如果不是通过stop()或close()方法,如何干净地停止Python中的ZeroRPC服务器?

回答

6

使用gevent.signal()来设置您的信号处理程序,而不是signal.signal()。

这是因为标准模块信号直接映射UNIX API,该API在gevent eventloop之外运行信号处理程序,而没有gevent greenlet/coroutine的任何概念。 gevent.signal与gevent ioloop集成,并确保在其自己的greenlet中执行您的信号处理程序。

GEVENT兼容的解决方案:

import zerorpc, sys, gevent, signal, os 

class MyClass: 
     pass 

if __name__ == '__main__': 
    zpc = zerorpc.Server(MyClass) 
    zpc.bind('ipc://./mysocket.sock') 
    gevent.signal(signal.SIGTERM, zpc.stop) 
    zpc.run() 
    print("zpc stopped"); sys.stdout.flush() 
+0

好极了,那完美。我继续在zpc.run()之后抛出zpc.close(),以确保套接字也从系统中清除。谢谢! – Thomas

+0

您不需要在.run()之后添加.close()!当.run()返回时,zerorpc服务器正常且干净地停止。看到一个更长的解释在这里:http://stackoverflow.com/questions/19208535/how-to-run-zerorpc-as-a-greenlet – bombela

+1

澄清我的意思是“清理掉” - 这是unix套接字,仍然在如果我只停止()服务器的路径。调用close()将删除该工件。 – Thomas

相关问题