2016-04-14 36 views
0

私はTornado Webアプリケーションを持っていますが、このアプリケーションはクライアントからGETおよびPOSTリクエストを受け取ることができます。Tornadoアプリケーションで複数のリクエストを受信する方法

POSTリクエストはTornado Queueで受け取った情報を入れてから、キューからこの情報をポップし、データベースで操作します。この操作は非常に遅く、完了するまでに数秒かかることがあります。

その間、このデータベース操作は、他のPOST(キューに他の情報を入れる)とGETを受け取ることができるようにしたいと考えています。代わりにGETは非常に高速であり、結果を即座にクライアントに返さなければなりません。

問題は、キューからポップして低速操作を開始すると、サーバーがクライアントからの他の要求を受け入れないということです。どうすれば解決できますか?私は、行の5 POSTをすれば、それは置いなぜ

# URLs are defined in a config file 
application = tornado.web.Application([ 
    (BASE_URL, Variazioni), 
    (ARTICLE_URL, Variazioni), 
    (PROMO_URL, Variazioni), 
    (GET_FEEDBACK_URL, Feedback) 
]) 

class Server: 

    def __init__(self): 
     http_server = tornado.httpserver.HTTPServer(application, decompress_request=True) 
     http_server.bind(8889) 
     http_server.start(0) 

     transactions = TransactionsQueue() #contains the queue and the function with interact with it 
     IOLoop.instance().add_callback(transactions.process) 

    def start(self): 
     try: 
      IOLoop.instance().start() 
     except KeyboardInterrupt: 
      IOLoop.instance().stop() 

if __name__ == "__main__": 
    server = Server() 
    server.start() 



class Variazioni(tornado.web.RequestHandler): 
    ''' Handle the POST request. Put an the data received in the queue ''' 

    @gen.coroutine 
    def post(self): 
     TransactionsQueue.put(self.request.body) 
     self.set_header("Location", FEEDBACK_URL) 


class TransactionsQueue: 
    ''' Handle the queue that contains the data 
     When a new request arrive, the generated uuid is putted in the queue 
     When the data is popped out, it begin the operation on the database 
    ''' 

    queue = Queue(maxsize=3) 

    @staticmethod 
    def put(request_uuid): 
     ''' Insert in the queue the uuid in postgres format ''' 
     TransactionsQueue.queue.put(request_uuid) 


    @gen.coroutine 
    def process(self): 
     ''' Loop over the queue and load the data in the database ''' 
     while True: 
      # request_uuid is in postgres format 
      transaction = yield TransactionsQueue.queue.get() 
      try: 
       # this is the slow operation on the database 
       yield self._load_json_in_db(transaction) 
      finally: 
       TransactionsQueue.queue.task_done() 

はまた、私は理解していない:

これは私がこれまで書いてきたsemplifiedコードです(インポートは、テキストの回避壁のために省略されています)待ち行列内の5つのデータは最大サイズは3ですが、

答えて

1

私は同期データベースドライバを使用していると推測しています。したがって、コルーチンではありますが、_load_json_in_dbは実際には非同期ではありません。したがって、長い操作が完了するまで、イベントループ全体がブロックされます。そのため、サーバーは操作が完了するまで、さらに多くの要求を受け付けません。

_load_json_in_dbはイベントループをブロックするので、実行中にTornadoはさらに多くのリクエストを受け入れることができないため、キューは決して最大サイズまで拡大しません。

2つの修正が必要です。

まず、Tornado専用の非同期データベースドライバを使用するか、TornadoのThreadPoolExecutorを使用してスレッドに対してデータベース操作を実行します。それが終わっています一度

アプリケーションがキューを埋めることができるようになりますので、第二、TransactionsQueue.putは行う必要があります。私は何だと思います、キュー内の3つの項目が、すでに存在する場合

TransactionsQueue.queue.put_nowait(request_uuid) 

これは、例外がスローされますあなたは意図している。

+0

はい、私はpsycopg2を使用してデータベースにアクセスしています。私は 'ThreadPoolExecutor'を使用しようとしますが、これは今のところ最も簡単なことです。 質問:トルネード(momokoまたはクエリ)用のdbドライバを使用すると、 '_load_json_in_db'は常にコルーチンにする必要がありますか? – k4ppa

+0

修正; I/Oを実行するTornadoアプリケーション内の関数は、非同期で記述する必要があります。つまり、コルーチンでなければならず、後でI/Oの結果で実行されるコールバックが必要です。 –

関連する問題