1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
=====
Tasks
=====
.. module:: django.tasks
:synopsis: Django's built-in background Task system.
The Task framework provides the contract and plumbing for background work, not
the engine that runs it. The Tasks API defines how work is described, queued,
and tracked, but leaves actual execution to external infrastructure.
Task definition
===============
The ``task`` decorator
----------------------
.. function:: task(*, priority=0, queue_name="default", backend="default", takes_context=False, **kwargs)
The ``@task`` decorator defines a :class:`Task` instance. All keyword
arguments are passed directly to the backend's ``task_class`` (which
defaults to :class:`Task`).
The following standard arguments are supported:
* ``priority``: Sets the :attr:`~Task.priority` of the ``Task``. Defaults
to 0.
* ``queue_name``: Sets the :attr:`~Task.queue_name` of the ``Task``.
Defaults to ``"default"``.
* ``backend``: Sets the :attr:`~Task.backend` of the ``Task``. Defaults to
``"default"``.
* ``takes_context``: Controls whether the ``Task`` function accepts a
:class:`TaskContext`. Defaults to ``False``. See :ref:`Task context
<task-context>` for details.
Custom Task backends may define a custom ``task_class`` that accepts
additional arguments. These can be passed through the ``@task`` decorator::
@task(foo=5, bar=600)
def my_task():
pass
.. versionchanged:: 6.1
Support for passing arbitrary ``**kwargs`` to the ``@task`` decorator
is added.
If the defined ``Task`` is not valid according to the backend,
:exc:`~django.tasks.exceptions.InvalidTask` is raised.
See :ref:`defining tasks <defining-tasks>` for usage examples.
``Task``
--------
.. class:: Task
Represents a Task to be run in the background. Tasks should be defined
using the :func:`task` decorator.
Attributes of ``Task`` cannot be modified. See :ref:`modifying Tasks
<modifying-tasks>` for details.
.. attribute:: Task.priority
The priority of the ``Task``. Priorities must be between -100 and 100,
where larger numbers are higher priority, and will be run sooner.
The backend must have :attr:`.supports_priority` set to ``True`` to use
this feature.
.. attribute:: Task.backend
The alias of the backend the ``Task`` should be enqueued to. This must
match a backend defined in :setting:`BACKEND <TASKS-BACKEND>`.
.. attribute:: Task.queue_name
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>`, unless
:setting:`QUEUES <TASKS-QUEUES>` is set to ``[]``.
.. attribute:: Task.run_after
The earliest time the ``Task`` will be executed. This can be a
:class:`timedelta <datetime.timedelta>`, which is used relative to the
current time, a timezone-aware :class:`datetime <datetime.datetime>`,
or ``None`` if not constrained. Defaults to ``None``.
This attribute can be set using :meth:`~Task.using`.
The backend must have :attr:`.supports_defer` set to ``True`` to use
this feature. Otherwise,
:exc:`~django.tasks.exceptions.InvalidTask` is raised.
.. attribute:: Task.name
The name of the function decorated with :func:`task`. This name is not
necessarily unique.
.. method:: Task.using(*, priority=None, backend=None, queue_name=None, run_after=None)
Creates a new ``Task`` with modified defaults. The existing ``Task`` is
left unchanged.
``using`` allows modifying the following attributes:
* :attr:`priority <Task.priority>`
* :attr:`backend <Task.backend>`
* :attr:`queue_name <Task.queue_name>`
* :attr:`run_after <Task.run_after>`
See :ref:`modifying Tasks <modifying-tasks>` for usage examples.
.. method:: Task.enqueue(*args, **kwargs)
Enqueues the ``Task`` to the ``Task`` backend for later execution.
Arguments are passed to the ``Task``'s function after a round-trip
through a :func:`json.dumps`/:func:`json.loads` cycle. Hence, all
arguments must be JSON-serializable and preserve their type after the
round-trip.
If the ``Task`` is not valid according to the backend,
:exc:`~django.tasks.exceptions.InvalidTask` is raised.
See :ref:`enqueueing Tasks <enqueueing-tasks>` for usage examples.
.. method:: Task.aenqueue(*args, **kwargs)
The ``async`` variant of :meth:`enqueue <Task.enqueue>`.
.. method:: Task.get_result(result_id)
Retrieves a result by its id.
If the result does not exist, :exc:`TaskResultDoesNotExist
<django.tasks.exceptions.TaskResultDoesNotExist>` is raised. If the
result is not the same type as the current Task,
:exc:`TaskResultMismatch <django.tasks.exceptions.TaskResultMismatch>`
is raised. If the backend does not support ``get_result()``,
:exc:`NotImplementedError` is raised.
.. method:: Task.aget_result(*args, **kwargs)
The ``async`` variant of :meth:`get_result <Task.get_result>`.
Task context
============
.. class:: TaskContext
Contains context for the running :class:`Task`. Context only passed to a
``Task`` if it was defined with ``takes_context=True``.
Attributes of ``TaskContext`` cannot be modified.
.. attribute:: TaskContext.task_result
The :class:`TaskResult` currently being run.
.. attribute:: TaskContext.attempt
The number of the current execution attempts for this Task, starting at
1.
Task results
============
.. class:: TaskResultStatus
An Enum representing the status of a :class:`TaskResult`.
.. attribute:: TaskResultStatus.READY
The :class:`Task` has just been enqueued, or is ready to be executed
again.
.. attribute:: TaskResultStatus.RUNNING
The :class:`Task` is currently being executed.
.. attribute:: TaskResultStatus.FAILED
The :class:`Task` raised an exception during execution, or was unable
to start.
.. attribute:: TaskResultStatus.SUCCESSFUL
The :class:`Task` has finished executing successfully.
.. class:: TaskResult
The ``TaskResult`` stores the information about a specific execution of a
:class:`Task`.
Attributes of ``TaskResult`` cannot be modified.
.. attribute:: TaskResult.task
The :class:`Task` the result was enqueued for.
.. attribute:: TaskResult.id
A unique identifier for the result, which can be passed to
:meth:`Task.get_result`.
The format of the id will depend on the backend being used. Task result
ids are always strings less than 64 characters.
See :ref:`Task results <task-results>` for more details.
.. attribute:: TaskResult.status
The :class:`status <TaskResultStatus>` of the result.
.. attribute:: TaskResult.enqueued_at
The time when the ``Task`` was enqueued.
.. attribute:: TaskResult.started_at
The time when the ``Task`` began execution, on its first attempt.
.. attribute:: TaskResult.last_attempted_at
The time when the most recent ``Task`` run began execution.
.. attribute:: TaskResult.finished_at
The time when the ``Task`` finished execution, whether it failed or
succeeded.
.. attribute:: TaskResult.backend
The backend the result is from.
.. attribute:: TaskResult.errors
A list of :class:`TaskError` instances for the errors raised as part of
each execution of the Task.
.. attribute:: TaskResult.return_value
The return value from the ``Task`` function.
If the ``Task`` did not finish successfully, :exc:`ValueError` is
raised.
See :ref:`return values <task-return-values>` for usage examples.
.. method:: TaskResult.refresh
Refresh the result's attributes from the queue store.
.. method:: TaskResult.arefresh
The ``async`` variant of :meth:`TaskResult.refresh`.
.. attribute:: TaskResult.is_finished
Whether the ``Task`` has finished (successfully or not).
.. attribute:: TaskResult.attempts
The number of times the Task has been run.
If the task is currently running, it does not count as an attempt.
.. attribute:: TaskResult.worker_ids
The ids of the workers which have executed the Task.
Task errors
-----------
.. class:: TaskError
Contains information about the error raised during the execution of a
``Task``.
.. attribute:: TaskError.traceback
The traceback (as a string) from the raised exception when the ``Task``
failed.
.. attribute:: TaskError.exception_class
The exception class raised when executing the ``Task``.
Backends
========
Backends handle how Tasks are stored and executed. All backends share a common
interface defined by ``BaseTaskBackend``, which specifies the core methods for
enqueueing Tasks and retrieving results.
Base backend
------------
.. module:: django.tasks.backends.base
.. class:: BaseTaskBackend
``BaseTaskBackend`` is the parent class for all Task backends.
.. attribute:: BaseTaskBackend.task_class
The :class:`~django.tasks.Task` subclass to use when creating tasks
with the :func:`~django.tasks.task` decorator. Defaults to
:class:`~django.tasks.Task`. Custom backends can override this to use
a custom ``Task`` subclass with additional attributes.
.. attribute:: BaseTaskBackend.options
A dictionary of extra parameters for the Task backend. These are
provided using the :setting:`OPTIONS <TASKS-OPTIONS>` setting.
.. method:: BaseTaskBackend.enqueue(task, args, kwargs)
Task backends which subclass ``BaseTaskBackend`` should implement this
method as a minimum.
When implemented, ``enqueue()`` enqueues the ``task``, a :class:`.Task`
instance, for later execution. ``args`` are the positional arguments
and ``kwargs`` are the keyword arguments to be passed to the ``task``.
Returns a :class:`~django.tasks.TaskResult`.
.. method:: BaseTaskBackend.aenqueue(task, args, kwargs)
The ``async`` variant of :meth:`BaseTaskBackend.enqueue`.
.. method:: BaseTaskBackend.get_result(result_id)
Retrieve a result by its id. If the result does not exist,
:exc:`TaskResultDoesNotExist
<django.tasks.exceptions.TaskResultDoesNotExist>` is raised.
If the backend does not support ``get_result()``,
:exc:`NotImplementedError` is raised.
.. method:: BaseTaskBackend.aget_result(result_id)
The ``async`` variant of :meth:`BaseTaskBackend.get_result`.
.. method:: BaseTaskBackend.validate_task(task)
Validates whether the provided ``Task`` is able to be enqueued using
the backend. If the Task is not valid,
:exc:`InvalidTask <django.tasks.exceptions.InvalidTask>`
is raised.
Feature flags
~~~~~~~~~~~~~
Some backends may not support all features Django provides. It's possible to
identify the supported functionality of a backend, and potentially change
behavior accordingly.
.. attribute:: BaseTaskBackend.supports_defer
Whether the backend supports enqueueing Tasks to be executed after a
specific time using the :attr:`~django.tasks.Task.run_after` attribute.
.. attribute:: BaseTaskBackend.supports_async_task
Whether the backend supports enqueueing async functions (coroutines).
.. attribute:: BaseTaskBackend.supports_get_result
Whether the backend supports retrieving ``Task`` results from another
thread after they have been enqueued.
.. attribute:: BaseTaskBackend.supports_priority
Whether the backend supports executing Tasks as ordered by their
:attr:`~django.tasks.Task.priority`.
The below table notes which of the :ref:`built-in backends
<task-available-backends>` support which features:
============================ ======================= ===========================
Feature :class:`.DummyBackend` :class:`.ImmediateBackend`
============================ ======================= ===========================
:attr:`.supports_defer` Yes No
:attr:`.supports_async_task` Yes Yes
:attr:`.supports_get_result` No No [#fnimmediateresult]_
:attr:`.supports_priority` Yes [#fndummypriority]_ Yes [#fnimmediatepriority]_
============================ ======================= ===========================
.. _task-available-backends:
Available backends
------------------
Django includes only development and testing backends. These support local
execution and inspection, for production ready backends refer to
:ref:`configuring-a-task-backend`.
Immediate backend
~~~~~~~~~~~~~~~~~
.. module:: django.tasks.backends.immediate
.. class:: ImmediateBackend
The :ref:`immediate backend <immediate-task-backend>` executes Tasks
immediately, rather than in the background.
Dummy backend
~~~~~~~~~~~~~
.. module:: django.tasks.backends.dummy
.. class:: DummyBackend
The :ref:`dummy backend <dummy-task-backend>` does not execute enqueued
Tasks. Instead, it stores task results for later inspection.
.. attribute:: DummyBackend.results
A list of results for the enqueued Tasks, in the order they were
enqueued.
.. method:: DummyBackend.clear
Clears the list of stored results.
Exceptions
==========
.. module:: django.tasks.exceptions
.. exception:: InvalidTask
Raised when the :class:`.Task` attempting to be enqueued
is invalid.
.. exception:: InvalidTaskBackend
Raised when the requested :class:`.BaseTaskBackend` is invalid.
.. exception:: TaskResultDoesNotExist
Raised by :meth:`~django.tasks.backends.base.BaseTaskBackend.get_result`
when the provided ``result_id`` does not exist.
.. exception:: TaskResultMismatch
Raised by :meth:`~django.tasks.Task.get_result` when the provided
``result_id`` is for a different Task than the current Task.
.. rubric:: Footnotes
.. [#fnimmediateresult] The :class:`.ImmediateBackend` doesn't officially
support ``get_result()``, despite implementing the API, since the result
cannot be retrieved from a different thread.
.. [#fndummypriority] The :class:`.DummyBackend` has ``supports_priority=True``
so that it can be used as a drop-in replacement in tests. Since this
backend never executes Tasks, the ``priority`` value has no effect.
.. [#fnimmediatepriority] The :class:`.ImmediateBackend` has
``supports_priority=True`` so that it can be used as a drop-in replacement
in tests. Because Tasks run as soon as they are scheduled, the ``priority``
value has no effect.
|