1
0
mirror of https://github.com/django/django.git synced 2024-12-31 21:46:05 +00:00

Refs #33939 -- Improved transaction.on_commit() docs.

This commit is contained in:
Adam Johnson 2022-10-12 09:25:04 +01:00 committed by Mariusz Felisiak
parent e20c9eb60a
commit 444b6da7cc

View File

@ -290,45 +290,47 @@ Performing actions after commit
Sometimes you need to perform an action related to the current database
transaction, but only if the transaction successfully commits. Examples might
include a `Celery`_ task, an email notification, or a cache invalidation.
include a background task, an email notification, or a cache invalidation.
.. _Celery: https://pypi.org/project/celery/
Django provides the :func:`on_commit` function to register callback functions
that should be executed after a transaction is successfully committed:
:func:`on_commit` allows you to register callbacks that will be executed after
the open transaction is successfully committed:
.. function:: on_commit(func, using=None, robust=False)
Pass any function (that takes no arguments) to :func:`on_commit`::
Pass a function, or any callable, to :func:`on_commit`::
from django.db import transaction
def do_something():
pass # send a mail, invalidate a cache, fire off a Celery task, etc.
def send_welcome_email():
...
transaction.on_commit(do_something)
transaction.on_commit(send_welcome_email)
You can also bind arguments to your function using :func:`functools.partial`::
Callbacks will not be passed any arguments, but you can bind them with
:func:`functools.partial`::
from functools import partial
transaction.on_commit(partial(some_celery_task.delay, 'arg1'))
for user in users:
transaction.on_commit(
partial(send_invite_email, user=user)
)
The function you pass in will be called immediately after a hypothetical
database write made where ``on_commit()`` is called would be successfully
committed.
Callbacks are called after the open transaction is successfully committed. If
the transaction is instead rolled back (typically when an unhandled exception
is raised in an :func:`atomic` block), the callback will be discarded, and
never called.
If you call ``on_commit()`` while there isn't an active transaction, the
callback will be executed immediately.
If you call ``on_commit()`` while there isn't an open transaction,
the callback will be executed immediately.
If that hypothetical database write is instead rolled back (typically when an
unhandled exception is raised in an :func:`atomic` block), your function will
be discarded and never called.
It's sometimes useful to register callbacks that can fail. Passing
``robust=True`` allows the next callbacks to be executed even if the current
one throws an exception. All errors derived from Python's ``Exception`` class
are caught and logged to the ``django.db.backends.base`` logger.
It's sometimes useful to register callback functions that can fail. Passing
``robust=True`` allows the next functions to be executed even if the current
function throws an exception. All errors derived from Python's ``Exception``
class are caught and logged to the ``django.db.backends.base`` logger.
You can use :meth:`.TestCase.captureOnCommitCallbacks` to test callbacks
registered with :func:`on_commit`.
.. versionchanged:: 4.2
@ -390,8 +392,8 @@ Timing of execution
Your callbacks are executed *after* a successful commit, so a failure in a
callback will not cause the transaction to roll back. They are executed
conditionally upon the success of the transaction, but they are not *part* of
the transaction. For the intended use cases (mail notifications, Celery tasks,
etc.), this should be fine. If it's not (if your follow-up action is so
the transaction. For the intended use cases (mail notifications, background
tasks, etc.), this should be fine. If it's not (if your follow-up action is so
critical that its failure should mean the failure of the transaction itself),
then you don't want to use the :func:`on_commit` hook. Instead, you may want
`two-phase commit`_ such as the :ref:`psycopg Two-Phase Commit protocol support