Skip to content

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 SCHEDULES is configured) runs every max(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_ox is missing from INSTALLED_APPS.
  • django_ox.E002: a SCHEDULES entry 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.