Configuration
Everything django-ox reads lives in the standard TASKS setting, plus
three management commands. A full entry with every option spelled out:
TASKS = {
"default": {
"BACKEND": "django_ox.backend.OxBackend",
"QUEUES": ["default", "emails"],
"OPTIONS": {
"MAX_ATTEMPTS": 3,
"LOCK_TIMEOUT": 300,
"BACKOFF_INITIAL": 5,
"BACKOFF_MAX": 600,
"SCHEDULES": {}, # see the Recurring tasks page
},
}
}
Backend entry
| Key | Default | Meaning |
|---|---|---|
BACKEND |
required | "django_ox.backend.OxBackend". |
QUEUES |
["default"] |
Queue names tasks may be enqueued to. An empty list ([]) allows any queue name. Read by Django's Tasks framework itself. |
OPTIONS |
{} |
Backend options, below. |
OPTIONS
| Key | Default | Meaning |
|---|---|---|
MAX_ATTEMPTS |
3 |
Executions a task gets before it is marked FAILED. An attempt is consumed when a worker claims the task, so a worker dying mid-run counts too and retries stay bounded. |
LOCK_TIMEOUT |
300 |
Seconds a RUNNING task's lock may age before the reaper considers its worker dead and reclaims the task. Set it comfortably above your longest task. |
BACKOFF_INITIAL |
5 |
Delay in seconds before the first retry. |
BACKOFF_MAX |
600 |
Ceiling on the retry delay, in seconds. |
SCHEDULES |
{} |
Recurring task definitions. Documented on the Recurring tasks page. |
The retry delay after attempt n fails is
BACKOFF_INITIAL * 2 ** (n - 1), capped at BACKOFF_MAX. With the
defaults: 5 s, 10 s, 20 s, 40 s, and so on up to 600 s. There is no
jitter.
ox_worker
python manage.py ox_worker [options]
| Flag | Default | Meaning |
|---|---|---|
--backend |
default |
Backend alias from the TASKS setting. |
--queues |
all configured queues | Comma-separated queue names this worker processes. |
--concurrency |
1 |
Tasks executed concurrently, as a thread pool inside the process. |
--interval |
1.0 |
Polling interval in seconds when idle. When tasks are in flight the worker wakes as soon as one finishes, so this does not bound throughput. |
--lock-timeout |
backend LOCK_TIMEOUT, or 300 |
Seconds before a RUNNING task's lock is considered stale and the task is reclaimed. |
The command also honors Django's standard -v/--verbosity: at the default
verbosity it logs worker lifecycle and warnings to stderr, and -v 2
enables debug logging. -v 0 attaches no log handler.
Two intervals are derived rather than flagged:
- The reaper runs every
min(30, max(lock_timeout / 2, 1))seconds. - Schedule dispatch (when
SCHEDULESis configured) runs everymax(1, min(interval, 30))seconds, about once a second at the default polling interval.
If you embed the worker programmatically, django_ox.worker.Worker
accepts reap_interval, schedule_interval, backoff_initial and
backoff_max keyword overrides in addition to the flag equivalents.
ox_prune
Finished task rows stay in the table until pruned; the queue table doubles
as the result store, and django-ox does not guess at your retention
needs. Run ox_prune on your own schedule (cron or a systemd timer;
there is an example unit on the Production
page):
python manage.py ox_prune --older-than 7d
| Flag | Default | Meaning |
|---|---|---|
--older-than |
7d |
Minimum time since the task finished. Accepts 7d, 24h, 90m, 45s, or a plain number of seconds. |
--include-failed |
off | Also delete FAILED rows. By default they are kept, because they hold the per-attempt tracebacks. |
--batch-size |
1000 |
Rows per DELETE statement, so pruning a large table never takes a long lock or builds a giant IN clause. Must be at least 1. |
--dry-run |
off | Report how many rows would be deleted without deleting any. |
Only SUCCESSFUL rows (and, with --include-failed, FAILED rows) whose
finished_at is past the cutoff are deleted. READY and RUNNING rows are
never touched, whatever their age. Rows from the recurring-schedule tick
log are pruned with the same cutoff, always keeping each schedule's most
recent tick; that row anchors missed-tick recovery and deleting it would
make the schedule re-anchor. The latest tick row of a schedule that has
been removed from settings is kept by the same rule; such rows are
harmless and can be deleted by hand if unwanted. See
Recurring tasks.
ox_health
A health check for cron alerting and container probes: exits 0 when every enabled check passes, non-zero with a one-line reason otherwise. With no flags it verifies only that the database answers.
python manage.py ox_health --max-backlog 1000 --max-age 600
| Flag | Default | Meaning |
|---|---|---|
--queue |
all queues | Restrict the checks to one queue. |
--max-backlog |
off | Fail when more than this many READY tasks are eligible to run. Tasks deferred to a future run_after do not count. |
--max-age |
off | Fail when the oldest waiting task has waited longer than this many seconds since becoming eligible. |
--worker-timeout |
off | Fail when no worker has claimed a task within this many seconds, or no claim was ever recorded. |
Check semantics, probe examples, and guidance on which check fits which alert are on the Monitoring page.
System checks
manage.py check validates the setup:
django_ox.E001:django_oxis missing fromINSTALLED_APPS.django_ox.E002: aSCHEDULESentry is invalid (task path does not import, cron expression does not parse or can never fire, arguments not JSON-serializable, bad queue name or priority).django_ox.E003: the same schedule name is defined on more than one backend; schedule names must be unique across backends.
The worker performs the same schedule validation at startup, so a bad deploy fails loudly rather than skipping dispatches.