В чем разница между backend и broker в Celery
Что проверяют
Понимаете ли вы, что Celery состоит из независимых частей и что задача и её результат путешествуют разными путями. Следом обычно спрашивают, что будет, если backend не настроен, и какой брокер вы бы выбрали для продакшена.
Как отвечать
Разведите роли:
- broker: транспорт сообщений. Приложение кладёт туда задачу, воркер забирает. Задаётся
broker_url, основные варианты это RabbitMQ, Redis и Amazon SQS. Брокер отвечает за доставку и подтверждения, про результат он ничего не знает; - result backend: хранилище статусов и возвращаемых значений. Задаётся
result_backend: Redis, база через SQLAlchemy илиdjango-celery-results, Memcached,rpc://. Через него работаютAsyncResult.get(),.statusи примитивы canvas вродеchord.
Важная деталь: backend по умолчанию выключен. Без него задачи выполняются, но узнать результат нельзя. Если результат не нужен, его и не стоит хранить: ignore_result=True на задаче снимает лишнюю нагрузку. Хранятся результаты result_expires, по умолчанию сутки.
Дальше про выбор. RabbitMQ даёт полноценные подтверждения и маршрутизацию, Redis проще в эксплуатации, но у него есть visibility_timeout (по умолчанию час): неподтверждённую за это время задачу брокер отдаст другому воркеру, и задачи с eta дальше этого срока выполнятся повторно. Один Redis и как брокер, и как backend использовать можно, но это две разные роли, и разнести их хотя бы по разным базам Redis полезно.
Где спотыкаются
Говорят, что backend «хранит очередь». Очередь живёт в брокере, backend узнаёт о задаче только тогда, когда воркер записывает её статус.
Зовут result.get() внутри другой задачи. Это блокирует воркер и может привести к взаимоблокировке пула, поэтому Celery по умолчанию бросает на такой вызов RuntimeError. Для зависимых задач есть chain и chord.
Кладут в backend большие результаты: мегабайтные списки и целые файлы. Правильнее сохранить данные в хранилище, а из задачи вернуть ключ или путь.