2012-07-13 1 views
2

pyzmq official documentation에 설명 된대로 토네이도와 pyzmq ioloops를 결합하려고 시도했을 때 (치명적이지는 않지만) 하나의 성가신 문제가 발생했습니다.토네이도와 zmq ioloops 결합 : 피어 예외로 인한 연결 재설정

클라이언트 (C)로부터 REST API 요청을 받아들이고 실제 작업을 수행하는 다른 프로세스 (Z) 로의 ZMQ 전송을 통해 프록시하는 토네이도 (T) 서버를 실행하는 프로세스가 있습니다. C가 T로 연결을 Z 전에 회신을 닫으면

C <-> T <-> Z 

는 Z (토네이도) 예외 트레이스 긴 다발 (하단 참조)에 출력한다. 다음 예를 상상해

import tornado.ioloop 
from tornado.web import Application, RequestHandler, asynchronous 
from zmq.eventloop import ioloop 
import time 

def time_consuming_task(): 
    time.sleep(5) 

class TestHandler(RequestHandler): 
    def get(self, arg): 
     print "Test arg", arg 
     time_consuming_task() 
     print "Ok, time to reply" 
     self.write("Reply") 

if __name__ == "__main__": 
    app = tornado.web.Application(
     [ 
      (r"/test/([0-9]+)", TestHandler) 
     ]) 

    ioloop.install() 
    app.listen(8080) 
    tornado.ioloop.IOLoop.instance().start() 

이 예는 실제로 ZMQ 피어 얘기하지 않습니다, 그것은 단지의이 ioloop 토네이도하는 pyzmq의 ioloop을 첨부합니다. 하지만 문제를 설명하기에 충분합니다. 콘솔이 실행 클라이언트에서

% python example.py 

및 (5 초 동안 예) 서버가 응답하기 전에 중단 : 콘솔 하나 개 실행 서버에서

% curl -is http://localhost:8080/test/1 
^C 

서버의 출력은 다음과 같습니다

 
Test arg 1 
Ok, time to reply 
WARNING:root:Read error on 24: [Errno 54] Connection reset by peer 
ERROR:root:Uncaught exception GET /test/1 (::1) 
HTTPRequest(protocol='http', host='localhost:8080', method='GET', uri='/test/1', version='HTTP/1.1', remote_ip='::1', body='', headers={'Host': 'localhost:8080', 'Accept': '*/*', 'User-Agent': 'curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5'}) 
Traceback (most recent call last): 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1023, in _execute 
    self.finish() 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 701, in finish 
    self.request.finish() 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 433, in finish 
    self.connection.finish() 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 187, in finish 
    self._finish_request() 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 223, in _finish_request 
    self.stream.read_until(b("\r\n\r\n"), self._header_callback) 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 153, in read_until 
    self._try_inline_read() 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 386, in _try_inline_read 
    if self._read_to_buffer() == 0: 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 421, in _read_to_buffer 
    chunk = self._read_from_socket() 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 402, in _read_from_socket 
    chunk = self.socket.recv(self.read_chunk_size) 
error: [Errno 54] Connection reset by peer 
ERROR:root:Cannot send error response after headers written 
ERROR:root:Uncaught exception, closing connection. 
Traceback (most recent call last): 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 304, in wrapper 
    callback(*args) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 262, in _on_headers 
    self.request_callback(self._request) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1412, in __call__ 
    handler._execute(transforms, *args, **kwargs) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1025, in _execute 
    self._handle_request_exception(e) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1065, in _handle_request_exception 
    self.send_error(500, exc_info=sys.exc_info()) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 720, in send_error 
    self.finish() 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 700, in finish 
    self.flush(include_footers=True) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 660, in flush 
    self.request.write(headers + chunk, callback=callback) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 429, in write 
    self.connection.write(chunk, callback=callback) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 177, in write 
    assert self._request, "Request closed" 
AssertionError: Request closed 
ERROR:root:Exception in callback 
Traceback (most recent call last): 
    File "/Library/Python/2.7/site-packages/pyzmq-2.2.0-py2.7-macosx-10.7-intel.egg/zmq/eventloop/ioloop.py", line 434, in _run_callback 
    callback() 
    File "/Library/Python/2.7/site-packages/tornado/iostream.py", line 304, in wrapper 
    callback(*args) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 262, in _on_headers 
    self.request_callback(self._request) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1412, in __call__ 
    handler._execute(transforms, *args, **kwargs) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1025, in _execute 
    self._handle_request_exception(e) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 1065, in _handle_request_exception 
    self.send_error(500, exc_info=sys.exc_info()) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 720, in send_error 
    self.finish() 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 700, in finish 
    self.flush(include_footers=True) 
    File "/Library/Python/2.7/site-packages/tornado/web.py", line 660, in flush 
    self.request.write(headers + chunk, callback=callback) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 429, in write 
    self.connection.write(chunk, callback=callback) 
    File "/Library/Python/2.7/site-packages/tornado/httpserver.py", line 177, in write 
    assert self._request, "Request closed" 
AssertionError: Request closed 

참고 : 그것은 pyzmq rel 인 것 같습니다. pyzmq ioloop을 제외한 후에 사라지는 문제.

서버가 죽지 않아 다른 클라이언트에서 사용할 수 있으므로 문제가 심각하지 않습니다. 로그 파일에서 이러한 큰 혼란스러운 흔적을 발견하는 것은 매우 성가시다.

그래서이 문제를 해결할 수있는 잘 알려진 방법이 있습니까? 감사합니다. .

답변

0

ZMQ 문제가 아닙니다. 요청은 시간 초과 사유 이외의 방법으로 닫을 수 있습니다. ZMQ의 유일한 문제는 더 구체적인 예외 대신에 공통적 인 AssertionError을 발생시키고 있다는 것입니다.

당신은 당신이 로그 파일에 이러한 예외를 갖고 싶어하지 않는 것이, 확실한 경우 - 같은 것을 수행

try: 
    time_consuming_task() 
except AssertionError as e: 
    if e.message == 'Request closed': 
     logging.info('Bad, annoying client, came to us again!') 
    else: 
     raise e