Запрос торнадо с обратным вызовом WebSocket - PullRequest
0 голосов
/ 09 июня 2018

Я пытаюсь запустить функцию длинной блокировки после получения HTTP-запроса.На запрос необходимо ответить немедленно (200 OK или 500 Internal Error), но процесс должен работать в фоновом режиме и отправить уведомление в WebSocket после завершения.

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

Я использую add_callback, но я не уверен, является ли это правильным способом использования торнадо, так как он блокирует входящие HTTP-запросы.Я пытался использовать разные потоки, но у меня возникли исключения при попытке вызвать метод send_message из обработчика WebSocket.

import time
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.web import Application, RequestHandler, asynchronous
from tornado.websocket import WebSocketHandler


def long_process(id):
    time.sleep(5)


class RequestWeb(RequestHandler):
    @gen.coroutine
    def process(self, id):
        # Trying to call long_process, just like
        # yield gen.Task(IOLoop.current().add_timeout, time.time() + 10)
        # The response must be sent inmediately, but the process should run in the background
        IOLoop.current().add_callback(callback=lambda: long_process(id))

    @asynchronous
    @gen.coroutine
    def get(self, id):
        IOLoop.current().add_future(self.process(id), self.process_complete)
        self.write("OK")

    def process_complete(self, future):
        SocketHandler.send_message('Processing complete')


class SocketHandler(WebSocketHandler):
    connections = set()

    def open(self):
        SocketHandler.connections.add(self)

    @classmethod
    def send_message(cls, message):
        for ws in cls.connections:
            ws.write_message(message)


def make_app():
    return Application([
        (r'/api/(?P<id>[a-zA-Z0-9]+)$', RequestWeb),
        (r'/ws', SocketHandler)
    ])


if __name__ == "__main__":
    app = make_app()
    app.listen(8000)
    IOLoop.current().start()
...