2016-04-14 50 views
0

我有一个Tornado Web应用程序,此应用程序可以从客户端接收GET和POST请求。如何在Tornado应用程序中接收多个请求

POSTs请求会在Tornado队列中收到一条信息,然后我从队列中弹出这个信息,并用它对数据库进行操作,该操作可能非常缓慢,可能需要几秒钟才能完成!

在此期间,数据库操作继续我希望能够接收其他POST(将其他信息放入队列中)和GET。 GET的速度非常快,必须立即返回客户端的结果。

问题是,当我从队列中弹出并且慢速操作开始时,服务器不接受来自客户端的其他请求。我该如何解决这个问题?

这是semplified代码到目前为止我已经写了(进口,省略了文本的避免墙体):

# 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() 

而且我不明白为什么,如果我做一排5 POST,它把尽管最大尺寸是3,但队列中的所有五个数据都是3.

回答

1

我猜测你使用的是同步数据库驱动程序,所以_load_json_in_db虽然是一个协程,但实际上并不是异步的。因此它将阻止整个事件循环,直到长操作完成。这就是服务器在操作完成之前不接受更多请求的原因。

由于_load_json_in_db会阻止事件循环,因此Tornado在运行时无法接受更多请求,所以您的队列永远不会增长到其最大大小。

您需要两个修复程序。

首先,使用专门为Tornado编写的异步数据库驱动程序,或使用Tornado的ThreadPoolExecutor在线程上运行数据库操作。

一旦这样做了你的应用程序将能够填补队列,那么第二,TransactionsQueue.put必须做到:

TransactionsQueue.queue.put_nowait(request_uuid) 

这将引发异常,如果有已经在队列3项,我认为这是什么你打算。

+0

是的,我使用psycopg2来访问数据库。我会尝试使用'ThreadPoolExecutor',这似乎是现在最简单的事情。 问题:如果我使用数据库驱动程序龙卷风(momoko或查询)'_load_json_in_db'必须永远是一个协程? – k4ppa

+0

正确;在I/O的Tornado应用程序中的任何函数都必须异步写入:也就是说,它必须是一个协程,或者它必须采用稍后执行的I/O结果的回调函数。 –

相关问题