2014-01-15 4 views
2

나는 이보다 더 많은 코드를 가지고 있으므로 관련성이있는 것으로 트리밍하고 있습니다.ZeroRPC 파이썬 서버가 멈추거나 닫힐 때 예외가 발생했습니다.

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

파이썬 스크립트가 표준 출력 및 표준 오류에 수신 내 Node.js를 서버에서 ChildProcess으로 산란되어 문서화 된 예에 따라, 나는 ZeroRPC 사용하기위한 파이썬 클래스가 있습니다. 클라이언트 연결 시간이 초과되거나 서버가 종료되면 SIGTERM을 보내는 ChildProcess에 kill()을 호출합니다.

위의 코드를 사용하면 ZeroRPC 서버가 실행 루프의 어딘가에서 종료된다는 것을 나타내는 Node.js 콜백에서 'zpc stopped'이 캡처되지 않습니다. 또한 소켓 파일이 남아있어 서버가 소켓을 닫지 않음을 나타냅니다.

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 

변경 정지 : 예외는 자사의 표준 오류 콜백을 통해 Node.js를에 의해 선택됩니다

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) 

: 그래서 생각 나는 SIGTERM을 캡처 한 후 서버에 정지() 또는 가까운()를 호출 할 것이다() to close()는 동일한 궁극적 인 예외 집합을 발생시킵니다. Javascript (Node.js)에서 같은 아이디어를 구현하는 close()는 예외 나 경고를 던지지 않고 실행중인 서버 (디렉토리의 소켓 파일)를 정리합니다.

이 모든 질문은 stop() 또는 close()가 아닌 경우 어떻게 파이썬에서 ZeroRPC 서버를 완전히 멈추게합니까?

답변

6

signal.signal() 대신 신호 처리기를 설정하려면 gevent.signal()을 사용하십시오.

표준 모듈 신호는 gevent 이벤트 루프의 외부에서 신호 처리기를 실행하는 UNIX API를 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

"정리 된"의미를 명확히하기 위해 유닉스 소켓에 남아 있습니다. 경로는 서버를 중지() 만하면됩니다. close()를 호출하면 해당 이슈가 제거됩니다. – Thomas