Opened 40 minutes ago

Last modified 29 minutes ago

#37369 new New feature

on_commit should raise an error when no transaction is open

Reported by: Charlie Denton Owned by:
Component: Database layer (models, ORM) Version: 6.1
Severity: Normal Keywords:
Cc: Charlie Denton Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When calling on_commit outside of a transaction, Django will execute the callback immediately. This is a documented feature. See https://docs.djangoproject.com/en/6.1/topics/db/transactions/#performing-actions-after-commit

This leads to misleading code which looks as though it will defer work when it will not. For example, it masks issues where on_commit is called with a different using= argument to the transaction which is currently open. (Either the transaction was opened on the wrong DB, or the callback is waiting on the wrong database.)

Instead, it would make sense to adopt the behaviour of Django Subatomic's run_after_commit, which raises an error when on_commit is called outside of a transaction. After all, there will be no COMMIT when there is no open transaction.

This idea was suggested when on_commit was introduced, but was seemingly not addressed. See:

This has been discussed at Django on the Med 2026. The approach that was suggested to me was:

Step 1:

  • Change on_commit to raise an error when it is called without an open transaction.
  • Add a temporary setting to opt out of the new behaviour (and emit a warning when on_commit is called with no transaction).

Step 2:

  • Remove the opt-out setting.

To prevent a situation where code passes in tests but fails in production, we should explicitly ignore the transaction created by the test suite when checking if a transaction is open. Django Subatomic does this check using a utility function: in_transaction. I believe that function would be a useful addition to Django's API. See https://kraken-tech.github.io/django-subatomic/v2.0.0/reference/django_subatomic/db/#django_subatomic.db.in_transaction and https://github.com/django/new-features/issues/147.

The in_transaction API will enable developers who want to run the callback immediately if there is no transaction:

if in_transaction():
    on_commit(my_callback)
else:
    my_callback()

Change History (1)

comment:1 by Lily, 29 minutes ago

Triage Stage: UnreviewedAccepted
Note: See TracTickets for help on using tickets.
Back to Top