2016-04-14 7 views
0

У меня есть веб-приложение Tornado, это приложение может получать запросы GET и POST от клиента.Как получить несколько запросов в приложении Tornado

Запрос POSTs отправляет информацию, полученную в очередь Tornado Queue, затем я вывожу эту информацию из очереди, и с ней я выполняю операцию в базе данных, эта операция может быть очень медленной, это может занять несколько секунд!

Тем временем, когда эта операция с базой данных продолжается, я хочу иметь возможность получать другие POST (которые помещают другую информацию в очередь) и GET. GET вместо этого очень быстро и должны немедленно возвращать клиенту их результат.

Проблема в том, что когда я выхожу из очереди и медленная операция начинается, сервер не принимает другие запросы от клиента. Как я могу это решить?

Это код, который я упрощенный написал до сих пор (импорт опущены для избегайте стен текста):

# 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 в ряде, он положил все пять данных в очереди, хотя максимальный размер равен 3.

ответ

1

Я собираюсь угадать, что вы используете синхронный драйвер базы данных, поэтому _load_json_in_db, хотя это сопрограмма, на самом деле не асинхронная. Поэтому он блокирует весь цикл событий до завершения длительной операции. Вот почему сервер не принимает больше запросов до завершения операции.

С _load_json_in_db блокирует цикл событий, Tornado не может принимать больше запросов во время работы, поэтому ваша очередь никогда не увеличивается до максимального размера.

Вам нужны два исправления.

Прежде всего, используйте драйвер базы данных async, написанный специально для Tornado, или выполните операции с базами данных по потокам, используя Tornado's ThreadPoolExecutor.

После того, как это сделано ваше приложение будет иметь возможность заполнить очереди, поэтому второй, TransactionsQueue.put должен сделать:

TransactionsQueue.queue.put_nowait(request_uuid) 

Это бросает исключение, если уже есть 3 элементов в очереди, которые я думаю, что вы намерены.

+0

Да, я использую psycopg2 для доступа к базе данных. Я попытаюсь использовать «ThreadPoolExecutor», кажется, это самая простая вещь. Вопрос: если я использую драйвер db для торнадо (momoko или запросы), '_load_json_in_db' всегда должен быть сопрограммой? – k4ppa

+0

Исправить; любая функция в приложении Tornado, выполняющая операции ввода-вывода, должна быть написана асинхронно, то есть она должна быть сопрограммой, или она должна выполнить обратный вызов, который будет выполнен позже с результатом ввода-вывода. –

Смежные вопросы