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:
parent
e20c9eb60a
commit
444b6da7cc
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user