What's the correct way to use transaction.on_commit with Celery tasks in Django?

Approach 1: Without transaction.atomic

Source: https://adamj.eu/tech/2022/08/22/use-partial-with-djangos-transaction-on-commit/
def order_created(order):
    order.status = 'created'
    order.save()
    transaction.on_commit(
        partial(send_order_email.delay, order_id=order.id)
    )

Approach 2: With transaction.atomic

def order_created(order):
    with transaction.atomic():
        order.status = 'created'
        order.save()
        transaction.on_commit(
            partial(send_order_email.delay, order_id=order.id)
        )

Which approach is correct and why? The save() operation makes database changes, but examples differ on whether transaction.atomic is needed. (ATOMIC_REQUESTS=False in settings)

In the first example transaction.on_commit will result in error if there is no transaction open (related docs), plus save() will be executed right away so there is no need for on_commit at all.

In second example, Celery task will be queued at the end of successful transaction. As I understand your question, this is expected behaviour

Вернуться на верх