Я пытаюсь запустить функцию длинной блокировки после получения 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()