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

标签 javascript python node.js zeromq 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()

python 脚本作为 ChildProcess 从我的 Node.js 服务器生成,该服务器监听 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)

异常由 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

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

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

最佳答案

使用 gevent.signal() 代替 signal.signal() 来设置信号处理程序。

这是因为标准模块信号直接映射了 UNIX API,它在 gevent eventloop 之外运行信号处理程序,没有任何 gevent greenlet/coroutine 的概念。 gevent.signal 与 gevent ioloop 集成,并确保在 eventloop 中它自己的 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()

关于javascript - 尝试停止或关闭时 ZeroRPC python 服务器异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21140384/

相关文章:

javascript - NodeJS 理解事件队列

javascript - 单击链接时停止重定向

javascript - 我对 AngularJS 做错了什么?

python - 如何在 pygame 中添加一条线作为 Sprite ?

javascript - 作为 npm 模块安装并访问本地文件夹

node.js - 如何从服务访问 req(请求)属性

javascript - Node JS HTTP 代理挂了

javascript - 将 react-markdown 与 Material-UI 表一起使用

python - Entity Framework : Update multiple objects only if all objects exist

python - 如何使用 python 在函数中使用列表作为参数