Skip to content

Choosing a task backend

This page compares django-ox with the task queues a Django team is most likely to shortlist: django-tasks-db, huey, Celery, django-q2, dramatiq and procrastinate. Every cell about another project comes from that project's own documentation, source or issue tracker, with the link in the footnotes and the date it was read. Where a project's pages do not say, the cell says so rather than guessing.

The comparison is about fit, not ranking. A team that already runs RabbitMQ and needs to stop running tasks has a different answer from a team that wants one fewer service. The last section says where django-ox is not the right fit.

The table

django-ox django-tasks-db huey Celery django-q2 dramatiq procrastinate
django.tasks backend (Django 6) Yes, native Yes, native 1 No. Issue #870 closed 2025-11-14 9 No. Issue #10062 closed 2026-02-03 18 Pull request #315 open since 2026-02-04, last updated 2026-05-15 26 Not documented 29 Not documented; has its own Django integration 33
Broker needed None. The queue is a table in your database None. Django ORM 1 Redis, SQLite, PostgreSQL, file or memory storage 8 RabbitMQ, Redis or SQS (stable); Zookeeper, Kafka, Pub/Sub (experimental). SQL databases are result backends only 12. Issue #5149, PostgreSQL as a broker, open since 2018-10-25 with 95 upvotes 16 Redis (default), IronMQ, SQS, MongoDB or Django ORM 22 RabbitMQ or Redis 29 None. PostgreSQL is the queue 33
Transactional enqueue Yes. Enqueue is an INSERT on your connection; it commits or rolls back with your data Not documented 1 Not documented 8 No. Django's own docs name a background task as the case for on_commit() 21 Not documented 22 No. Enqueue is a broker send 29 Not documented 34
Retries and backoff Exponential backoff, MAX_ATTEMPTS, BACKOFF_INITIAL, BACKOFF_MAX; every attempt's traceback kept No retry option in the README or the worker flags 1 2 retries, retry_delay, retry_backoff 8 autoretry_for, retry_backoff, retry_backoff_max (default 600 s), retry_jitter 11 max_attempts (default 0, meaning unlimited) and a retry interval; backoff not documented 23 Exponential backoff; max_retries default 20, min_backoff 15 s, max_backoff 7 days 29 Retry strategy per task 33
Recurring schedules Cron in settings; every worker dispatches, no scheduler process None. Issue #259 open since 2026-08-10 7 periodic_task(crontab(...)) 8 celery beat, a separate process; "ensure only a single scheduler is running" 14 Schedule model, editable in admin; cron via croniter 24 None built in; APScheduler recommended 30 @app.periodic 33
Priorities -100 to 100 Yes 3 Yes; on Redis needs 5.0+ and PriorityRedisHuey 8 0 to 255 on RabbitMQ and Redis 15 Not documented 23 Per actor; lower number runs first 29 Yes 33
Time limit on a running task TASK_TIMEOUT, per queue in TASK_TIMEOUTS: TaskTimeout raised inside the task at the deadline, and a worker recycle when the thread does not stop. Two caveats leave the grace backstop as the whole enforcement: an interpreter with no facility for raising an exception in another thread, and a thread a coverage tool or debugger is watching. See Production Not documented in the README or the worker flags 1 2 timeout per task or per call; "a TaskTimeout is raised and returned to the caller via the result handle" 8 soft_time_limit raises SoftTimeLimitExceeded inside the task; time_limit terminates the process running it, which is replaced. "Time limits don't currently work on platforms that don't support the SIGUSR1 signal" 13 timeout, default None: "the number of seconds a worker is allowed to spend on a task before it's terminated" 23 time_limit per actor, default 10 minutes, raises TimeLimitExceeded. "Time limits are best-effort. They cannot cancel system calls or any function that doesn't currently hold the GIL under CPython" 29 Not documented on the page checked 33
Worker dies mid-task Lease renewed every LOCK_TIMEOUT / 3; a task whose lease goes stale for LOCK_TIMEOUT is put back to READY, or marked LOST when attempts are spent. See Production Issue #5, open since 2024-06-11: the task 'remains marked as "PROCESSING", and thus is never picked up for re-processing nor marked as completed / failed' 4 "tasks that are mid-execution are lost and will not be retried automatically" 8 acks_late re-delivers; the worker still acknowledges "if the child process executing the task is terminated" 11 Issue #327, open since 2026-05-05: worker death not reported to the monitor, MAX_ATTEMPTS ignored 27 Not stated on the pages checked 29 30 Heartbeat every 10 s; jobs stay in doing until a retry_stalled_jobs periodic task you define picks them up 35
Health and metrics ox_health command, django_ox.stats, a Prometheus endpoint (/ox/metrics), structured log events, admin retry and discard Issue #44, container healthchecks, open since 2026-06-08 5 Signals 8 Flower, a separate process, with Prometheus integration 20 qmonitor, qinfo, Stat 25 Prometheus middleware; not in the default middleware list 31 Statistics via events 33
Databases PostgreSQL, SQLite and MySQL 8 tested in CI; MariaDB 10.6+ untested Any Django database 1 Redis, SQLite, PostgreSQL, file, memory 8 Broker, not a database 12 Any Django database through the ORM broker 22 Broker, not a database 29 PostgreSQL 13+ 33
Licence BSD 3-Clause BSD 3-Clause 6 MIT 10 BSD 3-Clause 19 MIT 28 LGPL 3.0 32 MIT 36

Async tasks: django-ox sets supports_async_task, so async def tasks enqueue and run. Celery's most-upvoted open issue is #6552, "Support async function", open since 2020-12-19 with 98 upvotes 17.

When not to use django-ox

  • You need to stop one chosen task while it runs. django-ox bounds every attempt with TASK_TIMEOUT, discards a queued task and retries a failed one, but has no call that interrupts a particular running task on demand. Celery can revoke and terminate a running task, from Flower or the control API 20.
  • The queue must live on a different database from your models. Tasks are stored on the default database. Multi-database routing is outside the current scope, and a separate queue database would also give up the transactional enqueue.
  • Throughput beyond what one database comfortably serves. The benchmarks page gives measured numbers with the method. If your workload is above them, a broker-based queue is the right tool, and the cost is the second datastore.
  • Chains, groups and chords. Not in django-ox. Batches are in Oxpull Pro, a paid add-on that is not on sale yet; chains and workflows are on the Pro roadmap, undated.
  • CPU-bound tasks in one process. Worker concurrency is a thread pool. Run ox_worker --processes N --concurrency 1 for N interpreters, or pick a queue with a process pool.

Maintenance

Rows are re-checked each release. If a cell is out of date, open an issue with the link that shows it, and it will be corrected in the next release.


  1. https://github.com/RealOrangeOne/django-tasks-db README, checked 2026-08-23. 

  2. https://github.com/RealOrangeOne/django-tasks-db/blob/master/django_tasks_db/management/commands/db_worker.py, add_arguments, checked 2026-08-23. 

  3. https://github.com/RealOrangeOne/django-tasks-db/blob/master/django_tasks_db/backend.py, supports_priority = True, checked 2026-08-23. 

  4. https://github.com/RealOrangeOne/django-tasks-db/issues/5, open, checked 2026-08-23. 

  5. https://github.com/RealOrangeOne/django-tasks-db/issues/44, open, checked 2026-08-23. 

  6. https://github.com/RealOrangeOne/django-tasks-db, licence field, checked 2026-08-23. 

  7. https://github.com/RealOrangeOne/django-tasks/issues/259, open, checked 2026-08-23. 

  8. https://huey.readthedocs.io/en/latest/guide.html, checked 2026-08-23. 

  9. https://github.com/coleifer/huey/issues/870, closed, checked 2026-08-23. 

  10. https://github.com/coleifer/huey, licence field, checked 2026-08-23. 

  11. https://docs.celeryq.dev/en/stable/userguide/tasks.html, checked 2026-08-23. 

  12. https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/index.html, checked 2026-08-23. 

  13. https://docs.celeryq.dev/en/stable/userguide/workers.html, Time Limits, checked 2026-08-23. 

  14. https://docs.celeryq.dev/en/stable/userguide/periodic-tasks.html, checked 2026-08-23. 

  15. https://docs.celeryq.dev/en/stable/userguide/calling.html, checked 2026-08-23. 

  16. https://github.com/celery/celery/issues/5149, open, checked 2026-08-23. 

  17. https://github.com/celery/celery/issues/6552, open, checked 2026-08-23. 

  18. https://github.com/celery/celery/issues/10062, closed, checked 2026-08-23. 

  19. https://github.com/celery/celery/blob/main/LICENSE, checked 2026-08-23. 

  20. https://flower.readthedocs.io/en/latest/features.html, checked 2026-08-23. 

  21. https://docs.djangoproject.com/en/6.0/topics/db/transactions/#performing-actions-after-commit, checked 2026-08-23. 

  22. https://django-q2.readthedocs.io/en/master/brokers.html, checked 2026-08-23. 

  23. https://django-q2.readthedocs.io/en/master/configure.html, checked 2026-08-23. 

  24. https://django-q2.readthedocs.io/en/master/schedules.html, checked 2026-08-23. 

  25. https://django-q2.readthedocs.io/en/master/monitor.html, checked 2026-08-23. 

  26. https://github.com/django-q2/django-q2/pull/315, open, checked 2026-08-23. 

  27. https://github.com/django-q2/django-q2/issues/327, open, checked 2026-08-23. 

  28. https://github.com/django-q2/django-q2/blob/master/pyproject.toml, checked 2026-08-23. 

  29. https://dramatiq.io/guide.html, checked 2026-08-23. 

  30. https://dramatiq.io/cookbook.html, checked 2026-08-23. 

  31. https://github.com/Bogdanp/dramatiq/blob/master/dramatiq/middleware/init.py, default_middleware, and middleware/prometheus.py, checked 2026-08-23. 

  32. https://github.com/Bogdanp/dramatiq, licence field, checked 2026-08-23. 

  33. https://procrastinate.readthedocs.io/en/stable/, checked 2026-08-23. 

  34. https://procrastinate.readthedocs.io/en/stable/howto/django/basic_usage.html, checked 2026-08-23. 

  35. https://procrastinate.readthedocs.io/en/stable/howto/production/retry_stalled_jobs.html, checked 2026-08-23. 

  36. https://github.com/procrastinate-org/procrastinate, licence field, checked 2026-08-23.