2

Tornado を介して長いデータベースの結果セットをストリーミングしたいと考えています。クエリ全体をメモリにロードするのは現実的ではないため、明らかにサーバーカーソルが必要です。

だから私は次のコードを持っています:

class QueryStreamer(RequestHandler):

    def get(self):
      cursor.execute("Select * from ...")
      chunk = cursor.fetch(1000)
      while chunk:
          self.write(chunk)
          self.flush()
          chunk = cursor.fetch(1000)        
     self.finish()
     cursor.close()

誰かが私のリクエストを最後まで読まなかったら? (すなわちcurl ... |head)、getメソッドはどこにもデータをストリーミングし続けます。SIGPIPE私は、ある時点で取得してデータベースカーソルを閉じることを期待しています(何もせずに最後まで実行しません)。

Tornado で書き込みエラーをキャッチするにはどうすればよいですか?

更新:回答の提案に従って、次のことを試しました:

import tornado.ioloop
import tornado.web
import time

class PingHandler(tornado.web.RequestHandler):
        def get(self):
                for i in range(600):
                        self.write("pong\n")
                        self.flush()
                        time.sleep(1)
                        print "pong"
                self.finish()
                print "ponged"

        def on_connection_close(self):
                print "closed"

if __name__ == "__main__":
        application = tornado.web.Application([ ("/ping", PingHandler), ])
        application.listen(8888)
        tornado.ioloop.IOLoop.instance().start()

このファイルをターミナル 1 で実行し、ターミナル 2 で呼び出します。

curl -s   http://localhost:8888/ping

最初の応答の後、CTRL-C を押しました。しかし、ターミナル 1 では、喜んで「ポン」を鳴らし続け、on_connection_close呼び出されることはありません。

結論 - まだ機能しません。

4

2 に答える 2

7

ループをブロックするため、ハンドラーを非同期にして のioloop.add_timeout代わりに 使用する必要があります。time.sleep

import tornado.ioloop
import tornado.web
import tornado.gen


class PingHandler(tornado.web.RequestHandler):

    connection_closed = False

    def on_connection_close(self):
        print "closed"
        self.connection_closed = True

    @tornado.gen.coroutine  # <= async handler
    def get(self):

        for i in range(600):

            if self.connection_closed:
                # `on_connection_close()` has been called,
                # break out of the loop
                break

            self.write("pong %s\n" % i)
            self.flush()

            # Add a timeout. Similar to time.sleep(1), but non-blocking:
            yield tornado.gen.Task(
                tornado.ioloop.IOLoop.instance().add_timeout,
                tornado.ioloop.IOLoop.instance().time() + 1,
            )

        self.finish()
        print "finished"

if __name__ == "__main__":
    application = tornado.web.Application([("/ping", PingHandler), ])
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
于 2013-10-31T10:22:17.283 に答える
2

on_connection_closeメソッドを実装し、ハンドラでその書き込みループを停止させますget

于 2013-10-30T11:14:13.510 に答える