summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2022-10-12 09:25:04 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-11-04 12:20:25 +0100
commit444b6da7cc229a58a2c476a52e45233001dc7073 (patch)
tree71c4678e3b224c75ffaddec3e4ff80f9150361de
parente20c9eb60ab9d1c84b19672def918097c943edd8 (diff)
Refs #33939 -- Improved transaction.on_commit() docs.
-rw-r--r--docs/topics/db/transactions.txt52
1 files changed, 27 insertions, 25 deletions
diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
index 004f8351b8..d0b67b86f4 100644
--- a/docs/topics/db/transactions.txt
+++ b/docs/topics/db/transactions.txt
@@ -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