尝试停止或关闭时ZeroRPC python服务器异常

Tho*_*mas 2 javascript python zeromq node.js greenlets

我有比这更多的代码,所以我把它修改为看似相关的东西.根据记录的示例,我有一个用于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()
Run Code Online (Sandbox Code Playgroud)

python脚本从我的Node.js服务器生成为ChildProcess,它监听stdout和stderr.当客户端连接超时或服务器关闭时,我在ChildProcess上调用kill(),它向它发送SIGTERM.

仅使用上面的代码,'zpc stopped'永远不会在Node.js回调中捕获,这表明ZeroRPC服务器在其运行循环中的某处被杀死.此外,套接字文件仍然存在,表明服务器也没有关闭套接字.所以我想在捕获SIGTERM后我会在服务器上调用stop()或close():

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)
Run Code Online (Sandbox Code Playgroud)

Node.js通过其stderr回调获取异常:

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
Run Code Online (Sandbox Code Playgroud)

将stop()更改为close()会导致相同的最终异常集.在Javascript(Node.js)中实现相同的想法,close()清除正在运行的服务器(及其在目录中的套接字文件),而不会抛出任何异常或警告.

这一切都让我有了一个问题:如果不是通过stop()或close(),如何在Python中干净地停止ZeroRPC服务器?

小智 6

使用gevent.signal()设置信号处理程序而不是signal.signal().

这是因为标准模块信号直接映射UNIX 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()
Run Code Online (Sandbox Code Playgroud)