2

当我尝试按照pyzmq 官方文档中的描述组合 Tornado 和 pyzmq ioloops 时,我遇到了一个烦人的(虽然不是关键的)问题。

我有一个运行龙卷风(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 附加到 tornado 的 ioloop。不过,足以说明问题。

从控制台一台运行服务器:

% python example.py

从控制台二运行客户端并在服务器回复之前中断它(即在 5 秒内):

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

服务器的输出是:

测试参数 1
好的,到时候回复
WARNING:root:Read error on 24: [Errno 54] Connection reset by peer
错误:根:未捕获的异常 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'})
回溯(最近一次通话最后):
  _execute 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1023 行
    self.finish()
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 701 行,完成
    self.request.finish()
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 433 行,完成
    self.connection.finish()
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 187 行,完成
    self._finish_request()
  _finish_request 中的文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 223 行
    self.stream.read_until(b("\r\n\r\n"), self._header_callback)
  文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 153 行,在 read_until
    self._try_inline_read()
  _try_inline_read 中的文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 386 行
    如果 self._read_to_buffer() == 0:
  _read_to_buffer 中的文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 421 行
    块 = self._read_from_socket()
  _read_from_socket 中的文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 402 行
    块 = self.socket.recv(self.read_chunk_size)
错误:[Errno 54] 对等方重置连接
错误:root:写入标头后无法发送错误响应
错误:根:未捕获的异常,正在关闭连接。
回溯(最近一次通话最后):
  包装器中的文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 304 行
    回调(*args)
  _on_headers 中的文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 262 行
    self.request_callback(self._request)
  __call__ 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1412 行
    handler._execute(变换,*args,**kwargs)
  _execute 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1025 行
    self._handle_request_exception(e)
  _handle_request_exception 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1065 行
    self.send_error(500, exc_info=sys.exc_info())
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 720 行,在 send_error
    self.finish()
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 700 行,完成
    self.flush(include_footers=True)
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 660 行,齐平
    self.request.write(headers + chunk, callback=callback)
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 429 行,写入
    self.connection.write(块,回调=回调)
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 177 行,写入
    断言 self._request, "请求关闭"
AssertionError:请求已关闭
错误:root:回调中的异常
回溯(最近一次通话最后):
  _run_callback 中的文件“/Library/Python/2.7/site-packages/pyzmq-2.2.0-py2.7-macosx-10.7-intel.egg/zmq/eventloop/ioloop.py”,第 434 行
    打回来()
  包装器中的文件“/Library/Python/2.7/site-packages/tornado/iostream.py”,第 304 行
    回调(*args)
  _on_headers 中的文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 262 行
    self.request_callback(self._request)
  __call__ 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1412 行
    handler._execute(变换,*args,**kwargs)
  _execute 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1025 行
    self._handle_request_exception(e)
  _handle_request_exception 中的文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 1065 行
    self.send_error(500, exc_info=sys.exc_info())
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 720 行,在 send_error
    self.finish()
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 700 行,完成
    self.flush(include_footers=True)
  文件“/Library/Python/2.7/site-packages/tornado/web.py”,第 660 行,齐平
    self.request.write(headers + chunk, callback=callback)
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 429 行,写入
    self.connection.write(块,回调=回调)
  文件“/Library/Python/2.7/site-packages/tornado/httpserver.py”,第 177 行,写入
    断言 self._request, "请求关闭"
AssertionError:请求已关闭

注意:这似乎是与 pyzmq 相关的问题,因为在排除 pyzmq ioloop 后消失了。

服务器不会死,它可以被其他客户端使用,所以问题并不严重。但是,在日志文件中找到这些巨大的令人困惑的痕迹是非常烦人的。

那么,有没有什么众所周知的方法可以解决这个问题呢?谢谢。

4

1 回答 1

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
于 2012-07-16T06:50:17.210 回答