1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Various docs improvements

This commit is contained in:
Jake Howard 2024-12-13 17:25:22 +00:00
parent 97fee0a3c0
commit 725355c8b1
No known key found for this signature in database
GPG Key ID: 57AFB45680EDD477
2 changed files with 120 additions and 76 deletions

View File

@ -28,41 +28,41 @@ In the above example, ``calculate_meaning_of_life`` is a :class:`Task` instance.
* :attr:`queue_name <Task.queue_name>`
* :attr:`enqueue_on_commit <Task.enqueue_on_commit>`
If the task is not valid, according to the backend,
If the Task is not valid, according to the backend,
:exc:`django.tasks.exceptions.InvalidTaskError` is raised.
.. class:: Task
An class representing a task to be run in the background. Tasks should be
An class representing a Task to be run in the background. Tasks should be
defined using the :func:`task` decorator.
Attributes of ``Task`` cannot be modified.
.. attribute:: Task.priority
The priority of the task. Priorities must be between -100 and 100, where
The priority of the Task. Priorities must be between -100 and 100, where
larger numbers are higher priority, and will be run sooner.
By default, tasks are enqueued with a priority of 0.
By default, Tasks are enqueued with a priority of 0.
.. attribute:: Task.backend
The alias of the backend the task should be enqueued to.
The alias of the backend the Task should be enqueued to.
.. attribute:: Task.queue_name
The name of the queue the task will be enqueued on to. Defaults to
The name of the queue the Task will be enqueued on to. Defaults to
``"default"``.
This must match a queue defined in :setting:`QUEUES <TASKS-QUEUES>`.
.. attribute:: Task.run_after
The earliest time the task will be executed, or ``None`` to have no time set.
The earliest time the Task will be executed, or ``None`` to have no time set.
.. attribute:: Task.enqueue_on_commit
Whether the task should be enqueued when the transaction commits successfully,
Whether the Task should be enqueued when the transaction commits successfully,
or immediately.
By default, the behavior of the backend's
@ -70,13 +70,13 @@ Attributes of ``Task`` cannot be modified.
.. attribute:: Task.name
An identifier for a task. Potentially useful for debugging.
An identifier for a Task. Potentially useful for debugging.
A task's name is not necessarily unique.
A Task's name is not necessarily unique.
.. method:: Task.using()
Create a new task with modified defaults. The existing task is left unchanged.
Create a new Task with modified defaults. The existing Task is left unchanged.
``using`` allows modifying the following attributes:
@ -87,11 +87,11 @@ Attributes of ``Task`` cannot be modified.
.. method:: Task.enqueue(*args, **kwargs)
Enqueue the task for later execution.
Enqueue the Task for later execution.
Arguments and keyword arguments are passed to the task's function as-is.
Arguments and keyword arguments are passed to the Task's function as-is.
If the task is not valid, according to the backend,
If the Task is not valid, according to the backend,
:exc:`django.tasks.exceptions.InvalidTaskError` is raised.
.. method:: Task.aenqueue(*args, **kwargs)
@ -101,7 +101,7 @@ Attributes of ``Task`` cannot be modified.
.. method:: Task.get_result(result_id)
Retrieve a result by its id. If the result does not exist, or is not the same
type as the current task,
type as the current Task,
:exc:`ResultDoesNotExist <django.tasks.exceptions.ResultDoesNotExist>`
is raised.
@ -152,7 +152,7 @@ Attributes of ``TaskResult`` cannot be modified.
A unique identifier for the result, which can be passed to
:meth:`Task.get_result`.
The format of a task result id will depend on the backend being used.
The format of a Task result id will depend on the backend being used.
Some may use numbers, others UUIDs.
Task ids are always strings less than 64 characters.
@ -162,18 +162,18 @@ Attributes of ``TaskResult`` cannot be modified.
.. attribute:: TaskResult.enqueued_at
The time when the task was enqueued.
The time when the Task was enqueued.
If :attr:`Task.enqueue_on_commit` was set, this is the time the transaction
completed.
.. attribute:: TaskResult.started_at
The time when the task began execution.
The time when the Task began execution.
.. attribute:: TaskResult.finished_at
The time when the task finished execution, whether it failed or succeeded.
The time when the Task finished execution, whether it failed or succeeded.
.. attribute:: TaskResult.backend
@ -181,23 +181,23 @@ Attributes of ``TaskResult`` cannot be modified.
.. attribute:: TaskResult.exception_class
The exception class raised when executing the task.
The exception class raised when executing the Task.
If the task has not finished, ``ValueError`` is raised. If the task finished
If the Task has not finished, ``ValueError`` is raised. If the Task finished
successfully, the exception class is ``None``.
.. attribute:: TaskResult.traceback
The exception traceback from the raised exception when the task failed.
The exception traceback from the raised exception when the Task failed.
If the task has not finished, ``ValueError`` is raised. If the task finished
If the Task has not finished, ``ValueError`` is raised. If the Task finished
successfully, the traceback is ``None``.
.. attribute:: TaskResult.return_value
The return value from the task function.
The return value from the Task function.
If the task has not finished yet, or failed, :exc:`ValueError` is raised.
If the Task did not finish successfully, :exc:`ValueError` is raised.
.. method:: TaskResult.refresh
@ -209,7 +209,7 @@ Attributes of ``TaskResult`` cannot be modified.
.. attribute:: TaskResult.is_finished
Whether the task has finished (successfully or not).
Whether the Task has finished (successfully or not).
Backends
========
@ -221,7 +221,7 @@ Base backend
.. class:: BaseTaskBackend
``BaseTaskBackend`` is the parent class for all task backends.
``BaseTaskBackend`` is the parent class for all Task backends.
.. method:: BaseTaskBackend.get_result(result_id)
@ -245,7 +245,7 @@ changing behavior accordingly.
.. attribute:: BaseTaskBackend.supports_defer
Whether the backend supports enqueueing tasks to be
Whether the backend supports enqueueing Tasks to be
executed after a specific time using the ``run_after`` attribute.
.. attribute:: BaseTaskBackend.supports_async_task
@ -254,9 +254,19 @@ changing behavior accordingly.
.. attribute:: BaseTaskBackend.supports_get_result
Whether the backend supports retrieving task results from another thread
Whether the backend supports retrieving Task results from another thread
after they have been enqueued.
The below table notes which backends support which features:
======================= ================ ====================
Feature ``DummyBackend`` ``ImmediateBackend``
======================= ================ ====================
``supports_defer`` Yes No
``supports_async_task`` Yes Yes
``supports_get_result`` No No [#fimmediateresult]_
======================= ================ ====================
Available backends
------------------
@ -267,7 +277,7 @@ Immediate backend
.. class:: ImmediateBackend
The immediate backend executes tasks immediately, rather than in the background.
The immediate backend executes Tasks immediately, rather than in the background.
Dummy backend
~~~~~~~~~~~~~
@ -276,12 +286,12 @@ Dummy backend
.. class:: DummyBackend
The dummy backend doesn't execute enqueued tasks at all, instead storing results
The dummy backend doesn't execute enqueued Tasks at all, instead storing results
for later use.
.. attribute:: DummyBackend.results
A list of results for the enqueued tasks, in the order they were enqueued.
A list of results for the enqueued Tasks, in the order they were enqueued.
.. method:: DummyBackend.clear
@ -301,3 +311,8 @@ Exceptions
Raised when the :class:`Task <django.tasks.Task>` attempting to be
enqueued is invalid.
.. rubric:: Footnotes
.. [#fimmediateresult] The immediate backend doesn't officially support ``get_result``,
despite implementing the API, since the result cannot be retrieved from a
different thread.

View File

@ -21,7 +21,7 @@ execute the task, as well as a unique identifier for Django to retrieve the
result later.
Outside of Django, a Worker looks at the Queue Store for new Tasks to run. When
a new Task is added, the Worker claims the task, executes it, and saves the
a new Task is added, the Worker claims the Task, executes it, and saves the
status and result back to the Queue Store.
.. _configuring-a-task-backend:
@ -29,13 +29,14 @@ status and result back to the Queue Store.
Configuring a Task backend
==========================
Background tasks require some work to set up.
Different task backends have different characteristics and configuration options,
which may impact the performance and reliability of your application.
The Task backend determines how and where tasks are stored for execution and how
they are executed. Different task backends have different characteristics and
configuration options, which may impact the performance and reliability of your
application.
Task backends are configured using the :setting:`TASKS` setting in your settings
file.
file. Whilst most applications will only need a single backend, multiple are
supported.
.. _immediate-task-backend:
@ -47,25 +48,28 @@ The immediate backend runs enqueued tasks immediately, rather than in the
background. This allows background task functionality to be slowly added
to an application, before the required infrastructure is available.
To use it, set :setting:`BACKEND <TASKS-BACKEND>` to
``"django.tasks.backends.immediate.ImmediateBackend"``::
TASKS = {"default": {"BACKEND": "django.tasks.backends.immediate.ImmediateBackend"}}
The ``ImmediateBackend`` may also be useful in tests, to bypass the need to run a
real background worker in your tests.
.. warning::
When :setting:`ENQUEUE_ON_COMMIT <TASKS-ENQUEUE_ON_COMMIT>` is ``False``,
the task will be executed within the same transaction it was enqueued in.
This may lead to unexpected behavior changes when changing backend in future.
To use it, set :setting:`BACKEND <TASKS-BACKEND>` to
``"django.tasks.backends.immediate.ImmediateBackend"``::
TASKS = {"default": {"BACKEND": "django.tasks.backends.immediate.ImmediateBackend"}}
See :ref:`task_transactions` for more.
.. _dummy-task-backend:
Dummy backend
-------------
The dummy backend doesn't execute enqueued tasks at all, instead storing results
for later use.
The dummy backend doesn't execute enqueued Tasks at all, instead storing results
for later use. Task results will forever remain in the ``NEW`` state.
This backend is not intended for use in production - it is provided as a
convenience that can be used during development and testing.
@ -75,7 +79,7 @@ To use it, set :setting:`BACKEND <TASKS-BACKEND>` to
TASKS = {"default": {"BACKEND": "django.tasks.backends.dummy.DummyBackend"}}
The results for enqueued tasks can be retrieved from the backend's
The results for enqueued Tasks can be retrieved from the backend's
:attr:`results <django.tasks.backends.dummy.DummyBackend.results>` attribute::
from django.tasks import default_task_backend
@ -94,9 +98,9 @@ Stored results can be cleared using the
Using a custom backend
----------------------
While Django includes support for a number of task backends out-of-the-box,
sometimes you might want to customize the the task backend. To use an external
task backend with Django, use the Python import path as the
While Django includes support for a number of Task backends out-of-the-box,
sometimes you might want to customize the the Task backend. To use an external
Task backend with Django, use the Python import path as the
:setting:`BACKEND <TASKS-BACKEND>` of the :setting:`TASKS` setting, like so::
TASKS = {
@ -105,7 +109,7 @@ task backend with Django, use the Python import path as the
}
}
If you're building your own backend, you can use the standard task backends
If you're building your own backend, you can use the built-in Task backends
as reference implementations. You'll find the code in the
:source:`django/tasks/backends/` directory of the Django source.
@ -116,19 +120,19 @@ Each backend can be given additional arguments to control its behavior.
These arguments are provided as additional keys in the :setting:`TASKS` setting.
Valid arguments are as follows:
* :setting:`ENQUEUE_ON_COMMIT <TASKS-ENQUEUE_ON_COMMIT>`: Whether a task should
* :setting:`ENQUEUE_ON_COMMIT <TASKS-ENQUEUE_ON_COMMIT>`: Whether a Task should
be enqueued at the end of the current transaction (if there
is one) commits successfully, rather than enqueueing immediately. This argument
defaults to ``True``.
* :setting:`QUEUES <TASKS-QUEUES>`: Restrict the queue names a task may be
* :setting:`QUEUES <TASKS-QUEUES>`: Restrict the queue names a Task may be
enqueued to. By default, only the ``"default"`` queue is allowed. Queue name
validation can be disabled by setting this to an empty list.
Asynchronous support
--------------------
Django has developing support for asynchronous task backends.
Django has developing support for asynchronous Task backends.
``django.tasks.backends.base.BaseTaskBackend`` has async variants of all base
methods. By convention, the asynchronous versions of all methods are prefixed
@ -161,13 +165,13 @@ functionality, or use a system check to prevent the application from starting at
To facilitate this, certain features can be checked on a backend:
* :attr:`supports_defer <django.tasks.backends.base.BaseTaskBackend.supports_defer>`:
Can tasks be executed after a specific time using ``run_after``?
Can Tasks be executed after a specific time using ``run_after``?
* :attr:`supports_async_task <django.tasks.backends.base.BaseTaskBackend.supports_async_task>`:
Can ``async`` functions (coroutines) be used as task functions?
* :attr:`supports_get_result <django.tasks.backends.base.BaseTaskBackend.supports_get_result>`:
Can a task's results be retrieved from another thread or process?
Can a Task's results be retrieved from another thread or process?
Defining tasks
==============
@ -182,7 +186,7 @@ module-level function::
def calculate_meaning_of_life(answer=42):
return answer
Returned in a :class:`django.tasks.Task` instance.
The return value is a :class:`django.tasks.Task` instance.
.. note::
@ -190,31 +194,31 @@ Returned in a :class:`django.tasks.Task` instance.
as the same types.
This means complex types like model instances, as well as many built-in types
like ``datetime`` and ``tuple`` cannot be used in tasks without additional
like ``datetime`` and ``tuple`` cannot be used in Tasks without additional
conversion.
The ``task`` decorator accepts a few keyword arguments to customize the task:
The ``task`` decorator accepts a few keyword arguments to customize the Task:
* ``priority``: The priority of the task. Higher numbers will be executed sooner.
* ``priority``: The priority of the Task. Higher numbers will be executed sooner.
* ``queue_name``: The name of the queue the task will be executed on
* ``queue_name``: The name of the queue the Task will be executed on
* ``backend``: The name of the backend this task must use (as defined in
* ``backend``: The name of the backend this Task must use (as defined in
:setting:`TASKS`).
* ``enqueue_on_commit``: Whether the task is enqueued when the current transaction
* ``enqueue_on_commit``: Whether the Task is enqueued when the current transaction
commits successfully, or enqueued immediately.
These arguments correspond to attributes on the created
:class:`Task <django.tasks.Task>`.
By convention, tasks should be defined in a ``tasks.py`` file, however this is
By convention, Tasks should be defined in a ``tasks.py`` file, however this is
not enforced.
Modifying tasks
---------------
Before enqueueing tasks, it may be necessary to modify certain parameters of the task.
Before enqueueing Tasks, it may be necessary to modify certain parameters of the Task.
For example, to give it a higher priority than it would normally.
A ``Task`` instance cannot be modified directly. Instead, a modified instance
@ -236,10 +240,10 @@ the original as-is::
which is used relative to the current time (when ``using`` is called), or a
timezone-aware :class:`datetime <datetime.datetime>`.
Enqueueing tasks
Enqueueing Tasks
================
To add the task to the queue store, so it will be executed, call the ``enqueue``
To add the Task to the queue store, so it will be executed, call the ``enqueue``
method on it::
result = calculate_meaning_of_life.enqueue()
@ -254,17 +258,38 @@ If the task takes arguments, these can be passed as-is to ``enqueue``::
To enqueue tasks in an ``async`` context, :meth:`aenqueue <django.tasks.Task.aenqueue>`
is available as an ``async`` variant of ``enqueue``.
.. _task_transactions:
Transactions
------------
By default, tasks are enqueued after the current transaction (if there is one)
By default, tasks are enqueued after the current database transaction (if there is one)
commits successfully (using :meth:`transaction.on_commit <django.db.transaction.on_commit>`),
rather than enqueueing immediately.
rather than enqueueing immediately. For most backends, tasks are run in a
separate process, using a different database connection. Without waiting for the
transaction to commit, workers could start process a Task which uses objects which it
can't access yet.
This behavior can be changed by changing the :setting:`TASKS-ENQUEUE_ON_COMMIT`
setting for the backend, or for a specific task using the ``enqueue_on_commit``
parameter.
For example, consider this simplified example::
@task
def my_task():
Thing.objects.get()
with transaction.atomic():
Thing.objects.create()
my_task.enqueue()
If ``ENQUEUE_ON_COMMIT = False``, then it is possible for ``my_task`` to run before
the ``Thing`` is committed to the database, and the task won't be able to see
the created object within your transaction.
Task results
============
@ -287,7 +312,11 @@ result for ``calculate_meaning_of_life``, :exc:`django.tasks.exceptions.ResultDo
is raised.
To retrieve a ``TaskResult``, regardless of which kind of ``Task`` it was from,
use the ``get_result`` method on the API
use the ``get_result`` method on the backend::
from django.tasks import default_task_backend
result = default_task_backend.get_result(result_id)
To retrieve results in an ``async`` context, :meth:`aget_result <django.tasks.Task.aget_result>`
is available as an ``async`` variant of ``get_result`` on both the backend and ``Task``.
@ -298,8 +327,8 @@ Calling ``get_result`` on these backends will raise :exc:`NotImplementedError`.
Updating results
----------------
A ``TaskResult`` contains the status of a task's execution at the point it was
retrieved. If the task finishes after ``get_result`` is called, it will not update.
A ``TaskResult`` contains the status of a Task's execution at the point it was
retrieved. If the Task finishes after ``get_result`` is called, it will not update.
To refresh the values, call the :meth:`django.tasks.TaskResult.refresh` method::
@ -312,19 +341,19 @@ To refresh the values, call the :meth:`django.tasks.TaskResult.refresh` method::
Return values
-------------
If your task function returns something, it can be retrieved from the
If your Task function returns something, it can be retrieved from the
:attr:`django.tasks.TaskResult.return_value` attribute::
if result.status == ResultStatus.SUCCEEDED:
result.return_value # 42
If the task has not finished executing, or has failed, :exc:`ValueError` is raised.
If the Task has not finished executing, or has failed, :exc:`ValueError` is raised.
Exceptions
----------
If the task doesn't succeed, and instead raises an exception, either
as part of the task or as part of running it, the exception class is saved
If the Task doesn't succeed, and instead raises an exception, either
as part of the Task or as part of running it, the exception class is saved
to the :attr:`django.tasks.TaskResult.exception_class` attribute::
assert result.exception_class == ValueError