Как в Django правильно запустить асинхронную Celery-задачу внутри блока transaction.atomic, например для отправки email?

Постановку Celery-задачи нужно отложить через transaction.on_commit: воркер получит задание только после успешного commit, а не раньше появления данных в БД.

Короткий ответ

Что ответить на собеседовании

Постановку Celery-задачи нужно отложить через transaction.on_commit: воркер получит задание только после успешного commit, а не раньше появления данных в БД.

Подробный разбор

Ответ с пояснениями

Постановку Celery-задачи нужно отложить через transaction.on_commit: воркер получит задание только после успешного commit, а не раньше появления данных в БД.

В callback передавайте идентификатор объекта, а не ORM-экземпляр. Например: transaction.on_commit(partial(send_email.delay, user.pk)), предварительно импортировав partial из functools. При rollback callback не выполнится; при вложенном atomic дождётся внешней транзакции. Для задач на базе DjangoTask в Celery 5.4+ есть delay_on_commit. Это устраняет гонку с чтением незакоммиченных данных, но не гарантирует доставку при падении процесса после commit. Для такой гарантии нужен transactional outbox и идемпотентный обработчик.

Источник: docs.celeryq.dev.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее