当我尝试按照pyzmq official documentation中的描述组合Tornado和pyzmq ioloops时,我遇到了一个恼人的(虽然不是关键)问题。
我有一个运行tornado(T)服务器的进程,该服务器接受来自客户端(C)的REST API请求,并通过ZMQ传输到另一个执行实际工作的进程(Z)来代理它们。
C <-> T <-> Z
如果C在 Z回复T之前关闭连接,则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对等对话,它只是将pyzmq ioloop附加到龙卷风的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相关的问题,因为在排除pyzmq ioloop后消失了。
服务器不会死,它可以被其他客户端使用,因此问题并不重要。但是,在日志文件中找到这些巨大的混乱痕迹非常烦人。
那么,有没有任何众所周知的方法来解决这个问题? 感谢。
答案 0 :(得分: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