pyzmq 公式ドキュメントで説明されているように、Tornado と pyzmq ioloops を組み合わせようとしたときに、1 つの厄介な (重大ではありませんが) 問題に直面しました。
クライアント (C) からの REST API リクエストを受け入れ、実際の作業を行う別のプロセス (Z) に ZMQ トランスポートを介してそれらをプロキシするトルネード (T) サーバーを実行しているプロセスがあります。
C <-> T <-> Z
Z が T に応答する前にC が接続を閉じると、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 にアタッチするだけです。ただし、問題を説明するには十分です。
コンソール 1 実行サーバーから:
% python example.py
コンソール 2 からクライアントを実行し、サーバーが応答する前に (つまり 5 秒間) 中断します。
% curl -is http://localhost:8080/test/1
^C
サーバーの出力は次のとおりです。
テスト引数 1
わかりました、返信の時間です
WARNING:root:Read error on 24: [Errno 54] 接続がピアによってリセットされました
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'})
トレースバック (最新の呼び出しが最後):
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1023 行目、_execute 内
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()
ファイル "/Library/Python/2.7/site-packages/tornado/httpserver.py"、223 行目、_finish_request 内
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()
ファイル "/Library/Python/2.7/site-packages/tornado/iostream.py"、386 行目、_try_inline_read 内
self._read_to_buffer() == 0 の場合:
ファイル "/Library/Python/2.7/site-packages/tornado/iostream.py"、421 行目、_read_to_buffer 内
チャンク = self._read_from_socket()
ファイル "/Library/Python/2.7/site-packages/tornado/iostream.py"、402 行目、_read_from_socket 内
チャンク = self.socket.recv(self.read_chunk_size)
エラー: [Errno 54] ピアによって接続がリセットされました
ERROR:root:ヘッダーが書き込まれた後、エラー応答を送信できません
エラー:root:キャッチされない例外です。接続を閉じています。
トレースバック (最新の呼び出しが最後):
ファイル "/Library/Python/2.7/site-packages/tornado/iostream.py"、304 行目、ラッパー
コールバック(*args)
ファイル "/Library/Python/2.7/site-packages/tornado/httpserver.py"、262 行目、_on_headers 内
self.request_callback(self._request)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1412 行目、__call__ 内
handler._execute(transforms, *args, **kwargs)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1025 行目、_execute 内
self._handle_request_exception(e)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1065 行目、_handle_request_exception 内
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(ヘッダー + チャンク、コールバック = コールバック)
ファイル「/Library/Python/2.7/site-packages/tornado/httpserver.py」、429行目、書き込み中
self.connection.write(chunk, callback=callback)
ファイル「/Library/Python/2.7/site-packages/tornado/httpserver.py」、177行目、書き込み中
assert self._request、「リクエストはクローズされました」
AssertionError: リクエストがクローズされました
エラー:ルート:コールバックで例外が発生しました
トレースバック (最新の呼び出しが最後):
ファイル "/Library/Python/2.7/site-packages/pyzmq-2.2.0-py2.7-macosx-10.7-intel.egg/zmq/eventloop/ioloop.py"、434 行目、_run_callback 内
折り返し電話()
ファイル "/Library/Python/2.7/site-packages/tornado/iostream.py"、304 行目、ラッパー
コールバック(*args)
ファイル "/Library/Python/2.7/site-packages/tornado/httpserver.py"、262 行目、_on_headers 内
self.request_callback(self._request)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1412 行目、__call__ 内
handler._execute(transforms, *args, **kwargs)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1025 行目、_execute 内
self._handle_request_exception(e)
ファイル "/Library/Python/2.7/site-packages/tornado/web.py"、1065 行目、_handle_request_exception 内
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(ヘッダー + チャンク、コールバック = コールバック)
ファイル「/Library/Python/2.7/site-packages/tornado/httpserver.py」、429行目、書き込み中
self.connection.write(chunk, callback=callback)
ファイル「/Library/Python/2.7/site-packages/tornado/httpserver.py」、177行目、書き込み中
assert self._request、「リクエストはクローズされました」
AssertionError: リクエストがクローズされました
注: pyzmq ioloopを除外すると消えるため、pyzmq関連の問題のようです。
サーバーは停止せず、他のクライアントが使用できるため、問題は重大ではありません。ただし、ログファイルでこれらの巨大な紛らわしいトレースを見つけるのは非常に面倒です。
では、この問題を解決するためのよく知られた方法はありますか? ありがとう。