Какие альтернативы есть для фронтенда вместо постоянных запросов для проверки статуса задачи
Что проверяют
Понимаете ли вы, как доставить событие «задача готова» от фонового воркера до браузера и что для этого нужно на бэкенде. Следом спрашивают, как воркер Celery сообщит веб-процессу о завершении, если это разные процессы на разных машинах.
Как отвечать
Базовый контракт: запрос на запуск отвечает 202 Accepted с идентификатором задачи, дальше клиент узнаёт статус одним из способов:
- SSE: однонаправленный поток по обычному HTTP, в браузере
EventSourceс автоматическим переподключением и заголовкомLast-Event-ID. В FastAPI этоStreamingResponseс типомtext/event-streamили пакетsse-starlette, в Django асинхронныйStreamingHttpResponseпод ASGI. В nginx для такого маршрута выключают буферизацию; - WebSocket: двусторонний канал, нужен, если клиент тоже шлёт события. В Django это Channels с channel layer на Redis, в FastAPI встроенный
WebSocket. Нужен ASGI-сервер (Uvicorn, Daphne) и проксированиеUpgrade; - long polling: запрос висит, пока статус не изменится или не пройдёт секунд 20 или 30. Работает везде, но держит соединение открытым;
- polling с растущим интервалом: 1, 2, 4 секунды, сервер может подсказать паузу заголовком
Retry-After. Для редкой задачи это самый простой вариант; - вебхук: если клиент не браузер, а другой сервис, сервер сам вызывает его адрес по завершении.
Связка с воркером: задача Celery по завершении публикует событие в Redis pub/sub или в channel layer через async_to_sync(channel_layer.group_send), а веб-процесс пересылает его в открытые соединения. Статус заодно пишется в базу или Redis, чтобы его можно было запросить после переподключения.
Где спотыкаются
Держат SSE или long polling на синхронном Gunicorn с WSGI-воркерами. Каждое открытое соединение занимает воркер, и пара десятков вкладок кладёт сервис.
Ждут результат через AsyncResult.get() прямо в обработчике запроса. Это блокирующее ожидание, которое держит поток.
Считают SSE плохо поддерживаемым. Его понимают все современные браузеры, ограничение другое: на HTTP/1.1 браузер держит не больше шести соединений на домен, и каждая вкладка с EventSource занимает одно. На HTTP/2 проблема уходит.