Где лучше хранить состояние файла при опросе состояния документа раз в несколько секунд
Что проверяют
Понимаете ли вы, что частый опрос бьёт в одно место сотни раз в минуту, и где держать состояние, чтобы оно было общим для всех процессов и не нагружало базу. Следом обычно спрашивают, что изменится при нескольких инстансах и можно ли обойтись без опроса.
Как отвечать
Типичный сценарий: пользователь загрузил документ, фоновый воркер (Celery, RQ, Dramatiq) его обрабатывает, а фронтенд раз в несколько секунд спрашивает GET /documents/{id}/status. Варианты:
- память процесса: словарь или
lru_cacheне годятся. Подgunicornилиuvicornс несколькими воркерами у каждого процесса своя копия, обработчик вообще живёт в другом процессе, а при рестарте всё пропадает; - Redis: основное место для горячего статуса. Хэш
doc:{id}с полямиstate,progress,updated_atи TTL. Чтение за доли миллисекунды, операции атомарны, воркер пишет, API читает. У Celery для этого есть result backend в Redis; - база данных: источник правды для итогового статуса и истории. Колонка
statusвыдержит умеренный опрос, но тысячи клиентов с интервалом в секунду лучше увести в Redis.
Итог: промежуточный прогресс в Redis, финальный результат в базе. Нагрузку дополнительно снижают ETag с ответом 304 Not Modified и растущий интервал опроса. Если опрос мешает, переходите на push: SSE или WebSocket, а на бэкенде Redis Pub/Sub.
Если речь про изменение файла на диске, храните mtime, размер или хэш, а вместо цикла с os.stat берите watchdog (под Linux он работает через inotify).
Где спотыкаются
Держат состояние в глобальной переменной под threading.Lock. Блокировка работает внутри одного процесса и не спасает при нескольких воркерах.
Пишут прогресс в базу на каждый процент. Получается поток мелких UPDATE, от которого страдают остальные запросы.
Забывают про TTL: статусы брошенных задач копятся в Redis, пока не кончится память.