Как происходит запуск фоновой задачи в Celery по этапам
Что проверяют
Понимаете ли вы, что между delay() и выполнением задачи есть брокер, сериализация и воркер, и что на каждом шаге задача может потеряться или выполниться дважды. Следом спрашивают про acks_late, повторы и идемпотентность.
Как отвечать
Пройдите путь сообщения:
- вызов:
task.delay(4, 6)это короткая формаapply_async(args=(4, 6)). Во втором можно задатьcountdown,eta,queue,expires; - сообщение: Celery генерирует
task_id(UUID), сериализует имя задачи и аргументы, по умолчанию в JSON, и публикует сообщение в брокер, RabbitMQ или Redis. Без явной маршрутизации это очередьcelery. Вызывающий код сразу получаетAsyncResult; - воркер:
celery -A proj workerдержит пул процессов (по умолчанию prefork, по числу ядер) и забирает сообщения заранее. Сколько именно, задаётworker_prefetch_multiplier, по умолчанию 4 на процесс; - подтверждение: по умолчанию сообщение подтверждается перед выполнением. Упал воркер посреди задачи, и она потеряна. С
acks_late=Trueподтверждение идёт после выполнения, но задача может выполниться повторно, поэтому она обязана быть идемпотентной; - результат: статус и возвращаемое значение пишутся в result backend, если он настроен. Статус
STARTEDпоявляется только приtask_track_started=True, аPENDINGозначает и «ждёт», и «такой задачи не знаю»; - ошибки:
autoretry_for,retry_backoff,max_retries, либоself.retry()в задаче сbind=True.
Передавайте в задачу идентификаторы, а не ORM-объекты: к моменту выполнения данные в базе могут измениться, а объект в JSON просто не сериализуется.
Где спотыкаются
Вызывают delay() внутри незакоммиченной транзакции. Воркер берёт задачу раньше коммита и не находит запись. В Django задачу ставят через transaction.on_commit, в свежих версиях Celery для этого есть delay_on_commit().
Вызывают result.get() внутри другой задачи. Это прямой путь к взаимоблокировке, и Celery по умолчанию такой вызов запрещает.
С брокером Redis ставят eta или countdown дольше visibility_timeout (по умолчанию час). Сообщение считается потерянным и выполняется повторно.