2

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関連の問題のようです。

サーバーは停止せず、他のクライアントが使用できるため、問題は重大ではありません。ただし、ログファイルでこれらの巨大な紛らわしいトレースを見つけるのは非常に面倒です。

では、この問題を解決するためのよく知られた方法はありますか? ありがとう。

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 に答える