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関連の問題のようです。
サーバーは停止せず、他のクライアントが使用できるため、問題は重大ではありません。ただし、ログファイルでこれらの巨大な紛らわしいトレースを見つけるのは非常に面倒です。
では、この問題を解決するためのよく知られた方法はありますか? ありがとう。