dj-queue 0.4.0__tar.gz → 0.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dj_queue-0.4.0 → dj_queue-0.5.1}/PKG-INFO +191 -96
- {dj_queue-0.4.0 → dj_queue-0.5.1}/README.md +187 -94
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/admin.py +86 -18
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/api.py +68 -8
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/backend.py +4 -4
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/config.py +28 -4
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/contrib/asgi.py +15 -0
- dj_queue-0.5.1/dj_queue/contrib/prometheus.py +129 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/dashboard.py +44 -430
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/management/commands/dj_queue_health.py +8 -1
- dj_queue-0.5.1/dj_queue/migrations/0005_remove_recurringexecution_dj_queue_recurring_executions_task_key_run_at_unique_and_more.py +100 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/models/jobs.py +11 -11
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/models/recurring.py +13 -4
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/models/runtime.py +11 -1
- dj_queue-0.5.1/dj_queue/observability.py +476 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/operations/cleanup.py +11 -2
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/operations/concurrency.py +33 -11
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/operations/jobs.py +99 -39
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/operations/recurring.py +12 -3
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/base.py +5 -1
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/scheduler.py +3 -1
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/supervisor.py +20 -5
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_dashboard_process_rows.html +1 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/change_form.html +11 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/dashboard.html +4 -48
- dj_queue-0.5.1/dj_queue/urls.py +16 -0
- dj_queue-0.5.1/dj_queue/views.py +38 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/pyproject.toml +4 -2
- {dj_queue-0.4.0 → dj_queue-0.5.1}/LICENSE +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/apps.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/contrib/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/contrib/gunicorn.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/db.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/exceptions.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/hooks.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/log.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/management/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/management/commands/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/management/commands/dj_queue.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/management/commands/dj_queue_prune.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/migrations/0001_initial.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/migrations/0002_pause_semaphore.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/migrations/0003_recurringtask_recurringexecution.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/migrations/0004_dashboard.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/migrations/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/models/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/operations/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/routers.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/dispatcher.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/errors.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/interruptible.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/notify.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/pidfile.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/pool.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/procline.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/runtime/worker.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_dashboard_recurring_rows.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_dashboard_section_table.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_dashboard_semaphore_rows.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_paginator.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_queue_controls.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/_sortable_header_cells.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/change_list.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/includes/fieldset.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templates/admin/dj_queue/queue_jobs.html +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templatetags/__init__.py +0 -0
- {dj_queue-0.4.0 → dj_queue-0.5.1}/dj_queue/templatetags/dj_queue_admin.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dj-queue
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Database-backed task queue backend for Django
|
|
3
|
+
Version: 0.5.1
|
|
4
|
+
Summary: Database-backed task queue backend for Django’s Tasks framework.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -17,11 +17,13 @@ Requires-Dist: croniter>=6.2.2
|
|
|
17
17
|
Requires-Dist: django>=6.0.0
|
|
18
18
|
Requires-Dist: pyyaml>=6.0.3
|
|
19
19
|
Requires-Dist: psycopg>=3.3.3 ; extra == 'postgres'
|
|
20
|
+
Requires-Dist: prometheus-client>=0.4.0 ; extra == 'prometheus'
|
|
20
21
|
Requires-Python: >=3.12
|
|
21
22
|
Project-URL: Homepage, https://github.com/coriocactus/dj_queue
|
|
22
23
|
Project-URL: Repository, https://github.com/coriocactus/dj_queue
|
|
23
24
|
Project-URL: Issues, https://github.com/coriocactus/dj_queue/issues
|
|
24
25
|
Provides-Extra: postgres
|
|
26
|
+
Provides-Extra: prometheus
|
|
25
27
|
Description-Content-Type: text/markdown
|
|
26
28
|
|
|
27
29
|
# dj_queue
|
|
@@ -43,7 +45,7 @@ It keeps the queue, live execution state, runtime metadata, and task results in
|
|
|
43
45
|
- immediate, scheduled, recurring, and concurrency-limited work
|
|
44
46
|
|
|
45
47
|
`dj_queue` is inspired by Rails' [Solid Queue](https://github.com/rails/solid_queue),
|
|
46
|
-
|
|
48
|
+
shaped to fit Django's [task backend API](https://docs.djangoproject.com/en/6.0/topics/tasks/).
|
|
47
49
|
|
|
48
50
|
## Why dj_queue
|
|
49
51
|
|
|
@@ -71,20 +73,13 @@ Install the package:
|
|
|
71
73
|
pip install dj-queue
|
|
72
74
|
```
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
database adapter for you:
|
|
76
|
+
Optional extras:
|
|
76
77
|
|
|
77
78
|
```bash
|
|
78
|
-
pip install "dj-queue[postgres]"
|
|
79
|
+
pip install "dj-queue[postgres]" # psycopg for PostgreSQL + LISTEN/NOTIFY
|
|
80
|
+
pip install "dj-queue[prometheus]" # prometheus_client for /dj_queue/metrics
|
|
79
81
|
```
|
|
80
82
|
|
|
81
|
-
Notes:
|
|
82
|
-
|
|
83
|
-
- `postgres` installs `psycopg`, which Django's PostgreSQL backend and
|
|
84
|
-
`dj_queue`'s optional `LISTEN/NOTIFY` wakeups use
|
|
85
|
-
- for MySQL or MariaDB, install and configure a Django-compatible driver in
|
|
86
|
-
your application following Django's database docs
|
|
87
|
-
|
|
88
83
|
Add `dj_queue` to `INSTALLED_APPS`, register the router, and point Django's task
|
|
89
84
|
backend at `DjQueueBackend`:
|
|
90
85
|
|
|
@@ -164,12 +159,10 @@ If Django admin is installed, `dj_queue` adds an operator dashboard at
|
|
|
164
159
|
- queue, process, recurring-task, and semaphore overview
|
|
165
160
|
- backend-aware dashboard and raw changelists
|
|
166
161
|
- queue controls: pause, resume, clear ready
|
|
167
|
-
- job
|
|
168
|
-
-
|
|
169
|
-
-
|
|
170
|
-
- failed-job actions: retry and discard from list and detail views
|
|
162
|
+
- job actions: enqueue a fresh copy of any stored job
|
|
163
|
+
- failed jobs: retry and discard from list and detail views
|
|
164
|
+
- unschedule dynamic recurring tasks
|
|
171
165
|
- queue drill-down pages for state-specific inspection
|
|
172
|
-
- queue drill-down actions: discard ready, scheduled, and blocked jobs; retry or discard failed jobs; enqueue finished jobs again
|
|
173
166
|
|
|
174
167
|
**Dashboard overview**
|
|
175
168
|
|
|
@@ -328,54 +321,30 @@ Runners heartbeat into the queue database. If claimed work is left behind,
|
|
|
328
321
|
Use `python manage.py dj_queue_health` to check whether any fresh runtime
|
|
329
322
|
process rows exist for a backend.
|
|
330
323
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
| Backend | Support level | Notes |
|
|
334
|
-
|---|---|---|
|
|
335
|
-
| PostgreSQL | first-class | polling, `SKIP LOCKED`, and optional `LISTEN/NOTIFY` |
|
|
336
|
-
| MySQL 8+ | supported | polling plus `SKIP LOCKED` |
|
|
337
|
-
| MariaDB 10.6+ | supported | polling plus `SKIP LOCKED` |
|
|
338
|
-
| SQLite | supported with limits | polling only, serialized writes, no `SKIP LOCKED`, no `LISTEN/NOTIFY`; practical for development, CI, and smaller deployments |
|
|
339
|
-
|
|
340
|
-
Polling is the portability path everywhere. Backend-specific features improve
|
|
341
|
-
latency and throughput but are not correctness requirements.
|
|
342
|
-
|
|
343
|
-
## Data Contract
|
|
324
|
+
### Data Contract
|
|
344
325
|
|
|
345
|
-
Job payloads and persisted return values are stored in JSON columns, so they
|
|
346
|
-
must be JSON round-trippable.
|
|
326
|
+
Job payloads and persisted return values are stored in JSON columns, so they must be JSON round-trippable.
|
|
347
327
|
|
|
348
328
|
- enqueueing args or kwargs that cannot round-trip through JSON fails immediately
|
|
349
329
|
- returning a non-JSON-serializable value marks the job failed instead of
|
|
350
330
|
leaving it claimed forever
|
|
351
331
|
|
|
352
|
-
If you need to pass model instances, files, or custom objects, store them
|
|
353
|
-
elsewhere and pass identifiers or serialized data instead.
|
|
354
|
-
|
|
355
|
-
## Errors When Enqueuing
|
|
356
|
-
|
|
357
|
-
`DjQueueBackend.enqueue()` raises `dj_queue.exceptions.EnqueueError` for
|
|
358
|
-
backend-side validation failures instead of silently dropping work.
|
|
332
|
+
If you need to pass model instances, files, or custom objects, store them elsewhere and pass identifiers or serialized data instead.
|
|
359
333
|
|
|
360
|
-
|
|
334
|
+
## Database Support
|
|
361
335
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
-
|
|
365
|
-
|
|
366
|
-
|
|
336
|
+
| Backend | Support level | Notes |
|
|
337
|
+
|---|---|---|
|
|
338
|
+
| PostgreSQL | first-class | polling, `SKIP LOCKED`, and optional `LISTEN/NOTIFY` |
|
|
339
|
+
| MySQL 8+ | supported | polling plus `SKIP LOCKED` |
|
|
340
|
+
| MariaDB 10.6+ | supported | polling plus `SKIP LOCKED` |
|
|
341
|
+
| SQLite | supported with limits | polling only, serialized writes, no `SKIP LOCKED`, no `LISTEN/NOTIFY`; practical for development, CI, and smaller deployments |
|
|
367
342
|
|
|
368
|
-
|
|
369
|
-
from dj_queue.exceptions import EnqueueError
|
|
343
|
+
For MySQL or MariaDB, install and configure a Django-compatible driver following Django's database docs.
|
|
370
344
|
|
|
371
|
-
|
|
372
|
-
sync_account.enqueue(account_id, "refresh")
|
|
373
|
-
except EnqueueError as exc:
|
|
374
|
-
handle_enqueue_error(exc)
|
|
375
|
-
```
|
|
345
|
+
Polling is the portability path everywhere. Backend-specific features improve latency and throughput but are not correctness requirements.
|
|
376
346
|
|
|
377
|
-
|
|
378
|
-
inspectable in the queue database.
|
|
347
|
+
For production PostgreSQL operational guidance, see [Postgres Queue Health](#postgres-queue-health).
|
|
379
348
|
|
|
380
349
|
## Recurring Tasks
|
|
381
350
|
|
|
@@ -432,9 +401,10 @@ config.
|
|
|
432
401
|
The scheduler is part of the normal `dj_queue` runtime. You do not run a
|
|
433
402
|
separate recurring service.
|
|
434
403
|
|
|
435
|
-
|
|
404
|
+
Notes:
|
|
436
405
|
|
|
437
406
|
- schedules are cron expressions
|
|
407
|
+
- recurring task keys are scoped per backend alias
|
|
438
408
|
- only dynamic tasks can be unscheduled at runtime; unscheduling a static task returns `0`
|
|
439
409
|
- Django admin exposes the same unschedule operation on recurring-task list and detail views
|
|
440
410
|
- multiple schedulers sharing the same recurring config dedupe firing in the database
|
|
@@ -468,6 +438,10 @@ With this configuration:
|
|
|
468
438
|
- later jobs for the same key can block until capacity is released
|
|
469
439
|
- `on_conflict = "discard"` turns the same pattern into singleton-style work
|
|
470
440
|
|
|
441
|
+
Semaphore rows remain shared on the queue database. If you want per-backend
|
|
442
|
+
isolation for a limit, express that in the `concurrency_key` itself rather than
|
|
443
|
+
expecting one semaphore namespace per backend alias.
|
|
444
|
+
|
|
471
445
|
## Queue Operations
|
|
472
446
|
|
|
473
447
|
`QueueInfo` exposes operational queue controls without bypassing the queue
|
|
@@ -490,6 +464,7 @@ orders.clear()
|
|
|
490
464
|
Queue control notes:
|
|
491
465
|
|
|
492
466
|
- pausing a queue stops future claims, not enqueueing or already-claimed work
|
|
467
|
+
- pause rows are scoped per backend alias
|
|
493
468
|
- `clear()` discards ready jobs only
|
|
494
469
|
- pass `backend_alias=` when you want to target a non-default `TASKS` alias
|
|
495
470
|
|
|
@@ -549,6 +524,66 @@ except UndiscardableError:
|
|
|
549
524
|
|
|
550
525
|
Failures stay inspectable until you act on them.
|
|
551
526
|
|
|
527
|
+
## Errors When Enqueuing
|
|
528
|
+
|
|
529
|
+
`DjQueueBackend.enqueue()` raises `dj_queue.exceptions.EnqueueError` for
|
|
530
|
+
backend-side validation failures instead of silently dropping work.
|
|
531
|
+
|
|
532
|
+
Common reasons include:
|
|
533
|
+
|
|
534
|
+
- args or kwargs are not JSON round-trippable
|
|
535
|
+
- `concurrency_key` is set without `concurrency_limit`
|
|
536
|
+
- `concurrency_key` cannot be resolved from the enqueue arguments
|
|
537
|
+
- `concurrency_key` does not resolve to a non-empty string up to 255 chars
|
|
538
|
+
- `on_conflict` is not `"block"` or `"discard"`
|
|
539
|
+
|
|
540
|
+
```python
|
|
541
|
+
from dj_queue.exceptions import EnqueueError
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
sync_account.enqueue(account_id, "refresh")
|
|
545
|
+
except EnqueueError as exc:
|
|
546
|
+
handle_enqueue_error(exc)
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
Task execution errors are different: they become failed jobs and stay
|
|
550
|
+
inspectable in the queue database.
|
|
551
|
+
|
|
552
|
+
## Lifecycle Hooks
|
|
553
|
+
|
|
554
|
+
Register hooks before starting the runtime, typically during Django startup.
|
|
555
|
+
Each callback receives the live supervisor or runner instance.
|
|
556
|
+
|
|
557
|
+
```python
|
|
558
|
+
from dj_queue.hooks import on_start, on_worker_start, register_hook
|
|
559
|
+
|
|
560
|
+
@on_start
|
|
561
|
+
def supervisor_started(process):
|
|
562
|
+
print(process.name)
|
|
563
|
+
|
|
564
|
+
@on_worker_start
|
|
565
|
+
def worker_started(process):
|
|
566
|
+
print(process.metadata)
|
|
567
|
+
|
|
568
|
+
@register_hook("scheduler.exit")
|
|
569
|
+
def scheduler_exited(process):
|
|
570
|
+
print(process.name)
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Available hook helpers:
|
|
574
|
+
|
|
575
|
+
- supervisor: `on_start`, `on_stop`, `on_exit`
|
|
576
|
+
- worker: `on_worker_start`, `on_worker_stop`, `on_worker_exit`
|
|
577
|
+
- dispatcher: `on_dispatcher_start`, `on_dispatcher_stop`, `on_dispatcher_exit`
|
|
578
|
+
- scheduler: `on_scheduler_start`, `on_scheduler_stop`, `on_scheduler_exit`
|
|
579
|
+
- generic events: `register_hook("worker.start")`, `register_hook("dispatcher.stop")`, and so on
|
|
580
|
+
|
|
581
|
+
Hook notes:
|
|
582
|
+
|
|
583
|
+
- hooks fire in registration order
|
|
584
|
+
- hook failures do not block later hooks
|
|
585
|
+
- hook failures are isolated and routed through `on_thread_error`
|
|
586
|
+
|
|
552
587
|
## Multi-Database Setup
|
|
553
588
|
|
|
554
589
|
`dj_queue` can keep queue tables on a dedicated database alias.
|
|
@@ -591,6 +626,28 @@ python manage.py migrate dj_queue --database queue
|
|
|
591
626
|
With this setup, `dj_queue`'s ORM queries and raw SQL helpers stay on the queue
|
|
592
627
|
database.
|
|
593
628
|
|
|
629
|
+
## Postgres Queue Health
|
|
630
|
+
|
|
631
|
+
Operational and configuration guidance for scaling with `dj_queue` in
|
|
632
|
+
production PostgreSQL deployments, covering dedicated database setup, retention
|
|
633
|
+
policy, and autovacuum tuning.
|
|
634
|
+
|
|
635
|
+
- Use a dedicated queue database via `database_alias`. Keep reporting and
|
|
636
|
+
long-running transactions off the queue database.
|
|
637
|
+
- Keep retention short. Set `preserve_finished_jobs = False` if you do not need
|
|
638
|
+
successful results. Otherwise use bounded `clear_finished_jobs_after`,
|
|
639
|
+
`clear_failed_jobs_after`, and `clear_recurring_executions_after` values.
|
|
640
|
+
- Run `python manage.py dj_queue_prune` regularly for stricter cleanup.
|
|
641
|
+
- Keep `use_skip_locked = True` and `listen_notify = True` unless you have a
|
|
642
|
+
specific reason not to.
|
|
643
|
+
- Tune autovacuum for `dj_queue_jobs` and the high-churn
|
|
644
|
+
`dj_queue_*_executions` tables, often default OLTP settings are too
|
|
645
|
+
conservative for queue workloads.
|
|
646
|
+
- Keep transactions short across workers and the rest of your app. Long-lived
|
|
647
|
+
transactions pin dead tuples and delay vacuum.
|
|
648
|
+
- Monitor dead tuples, autovacuum frequency, and long-running queries before
|
|
649
|
+
reaching for partitioning or bulk-ingest paths.
|
|
650
|
+
|
|
594
651
|
## Embedded Server Mode
|
|
595
652
|
|
|
596
653
|
`dj_queue` can run inside an existing server process via embedded async
|
|
@@ -622,6 +679,21 @@ signal handling to the host server.
|
|
|
622
679
|
|
|
623
680
|
## Configuration
|
|
624
681
|
|
|
682
|
+
### Queues, backends, and databases
|
|
683
|
+
|
|
684
|
+
`dj_queue` has three separate routing concepts. Keep them distinct:
|
|
685
|
+
|
|
686
|
+
- `queue_name`: what kind of work this job is. Use it to route lanes inside one backend, such as `email`, `webhooks`, or `search-index`.
|
|
687
|
+
- `backend_alias`: which logical queue system owns the work. Use it when you want separate runtime config, recurring tasks, pause and process visibility, retention, or admin scoping.
|
|
688
|
+
- `database_alias`: where that backend's queue tables and runtime activity live. Use it when you want a dedicated database connection path or stronger storage isolation.
|
|
689
|
+
|
|
690
|
+
Common setup choices:
|
|
691
|
+
|
|
692
|
+
- one backend, one database: simplest and usually enough
|
|
693
|
+
- one backend, separate queue database: good when you want dedicated queue connections
|
|
694
|
+
- multiple backends, same database: good for logical and operational separation without another database
|
|
695
|
+
- multiple backends, multiple databases: use when you need stronger isolation and accept more migration and deployment complexity
|
|
696
|
+
|
|
625
697
|
### Deployment topology
|
|
626
698
|
|
|
627
699
|
Once migrations are in place, start processing jobs with `python manage.py dj_queue`
|
|
@@ -698,9 +770,13 @@ python manage.py dj_queue --config /etc/dj_queue.yml
|
|
|
698
770
|
DJ_QUEUE_CONFIG=/etc/dj_queue.yml python manage.py dj_queue
|
|
699
771
|
```
|
|
700
772
|
|
|
701
|
-
The YAML file
|
|
702
|
-
|
|
703
|
-
|
|
773
|
+
The YAML file is an overlay on `TASKS[backend_alias]["OPTIONS"]`. It supports
|
|
774
|
+
two shapes:
|
|
775
|
+
|
|
776
|
+
- a flat mapping of option values for the selected backend alias
|
|
777
|
+
- a `backends` mapping keyed by backend alias, where only the selected alias is applied
|
|
778
|
+
|
|
779
|
+
Flat mapping example:
|
|
704
780
|
|
|
705
781
|
```yaml
|
|
706
782
|
mode: async
|
|
@@ -737,8 +813,28 @@ recurring:
|
|
|
737
813
|
description: nightly cleanup
|
|
738
814
|
```
|
|
739
815
|
|
|
740
|
-
|
|
741
|
-
|
|
816
|
+
Multi-backend overlay example:
|
|
817
|
+
|
|
818
|
+
```yaml
|
|
819
|
+
backends:
|
|
820
|
+
default:
|
|
821
|
+
mode: async
|
|
822
|
+
database_alias: default
|
|
823
|
+
workers:
|
|
824
|
+
- queues: ["default", "email*"]
|
|
825
|
+
threads: 8
|
|
826
|
+
processes: 1
|
|
827
|
+
polling_interval: 0.1
|
|
828
|
+
|
|
829
|
+
critical:
|
|
830
|
+
mode: fork
|
|
831
|
+
database_alias: queue
|
|
832
|
+
workers:
|
|
833
|
+
- queues: ["alerts", "critical-review"]
|
|
834
|
+
threads: 2
|
|
835
|
+
processes: 1
|
|
836
|
+
polling_interval: 0.05
|
|
837
|
+
```
|
|
742
838
|
|
|
743
839
|
Environment overrides currently supported by `dj_queue` itself:
|
|
744
840
|
|
|
@@ -746,41 +842,6 @@ Environment overrides currently supported by `dj_queue` itself:
|
|
|
746
842
|
- `DJ_QUEUE_MODE`
|
|
747
843
|
- `DJ_QUEUE_SKIP_RECURRING`
|
|
748
844
|
|
|
749
|
-
## Lifecycle Hooks
|
|
750
|
-
|
|
751
|
-
Register hooks before starting the runtime, typically during Django startup.
|
|
752
|
-
Each callback receives the live supervisor or runner instance.
|
|
753
|
-
|
|
754
|
-
```python
|
|
755
|
-
from dj_queue.hooks import on_start, on_worker_start, register_hook
|
|
756
|
-
|
|
757
|
-
@on_start
|
|
758
|
-
def supervisor_started(process):
|
|
759
|
-
print(process.name)
|
|
760
|
-
|
|
761
|
-
@on_worker_start
|
|
762
|
-
def worker_started(process):
|
|
763
|
-
print(process.metadata)
|
|
764
|
-
|
|
765
|
-
@register_hook("scheduler.exit")
|
|
766
|
-
def scheduler_exited(process):
|
|
767
|
-
print(process.name)
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
Available hook helpers:
|
|
771
|
-
|
|
772
|
-
- supervisor: `on_start`, `on_stop`, `on_exit`
|
|
773
|
-
- worker: `on_worker_start`, `on_worker_stop`, `on_worker_exit`
|
|
774
|
-
- dispatcher: `on_dispatcher_start`, `on_dispatcher_stop`, `on_dispatcher_exit`
|
|
775
|
-
- scheduler: `on_scheduler_start`, `on_scheduler_stop`, `on_scheduler_exit`
|
|
776
|
-
- generic events: `register_hook("worker.start")`, `register_hook("dispatcher.stop")`, and so on
|
|
777
|
-
|
|
778
|
-
Hook notes:
|
|
779
|
-
|
|
780
|
-
- hooks fire in registration order
|
|
781
|
-
- hook failures do not block later hooks
|
|
782
|
-
- hook failures are isolated and routed through `on_thread_error`
|
|
783
|
-
|
|
784
845
|
### Runtime infrastructure errors
|
|
785
846
|
|
|
786
847
|
Set `on_thread_error` to a dotted callable path when you want custom handling
|
|
@@ -803,6 +864,40 @@ such as hook failures, heartbeat failures, notify-watcher failures, and managed
|
|
|
803
864
|
runner crashes. It is not used for exceptions raised by your task code; those
|
|
804
865
|
become failed jobs instead.
|
|
805
866
|
|
|
867
|
+
## Monitoring
|
|
868
|
+
|
|
869
|
+
Queue statistics are available in JSON via `/dj_queue/stats.json` and in
|
|
870
|
+
Prometheus text format via `/dj_queue/metrics`.
|
|
871
|
+
|
|
872
|
+
Include `dj_queue.urls` to expose them:
|
|
873
|
+
|
|
874
|
+
```python
|
|
875
|
+
urlpatterns += [path("dj_queue/", include("dj_queue.urls"))]
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
The `/dj_queue/metrics` endpoint requires the `prometheus` extra:
|
|
879
|
+
|
|
880
|
+
```bash
|
|
881
|
+
pip install "dj-queue[prometheus]"
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
Exported metric families:
|
|
885
|
+
|
|
886
|
+
- `dj_queue_queue_jobs{backend,queue,state}`
|
|
887
|
+
- `dj_queue_queue_paused{backend,queue}`
|
|
888
|
+
- `dj_queue_queue_latency_seconds{backend,queue}`
|
|
889
|
+
- `dj_queue_queue_live_workers{backend,queue}`
|
|
890
|
+
- `dj_queue_runner_processes{backend,status}`
|
|
891
|
+
- `dj_queue_runner_processes_by_kind{backend,kind,status}`
|
|
892
|
+
- `dj_queue_recurring_tasks{backend}`
|
|
893
|
+
- `dj_queue_semaphores{queue_database}`
|
|
894
|
+
- `dj_queue_process_rows{backend}`
|
|
895
|
+
|
|
896
|
+
Both endpoints support bearer token authentication. Set
|
|
897
|
+
`DJ_QUEUE_OBSERVABILITY_TOKEN` in `settings.py` and include it as
|
|
898
|
+
`Authorization: Bearer <token>`. Leave it unset if you protect these URLs at
|
|
899
|
+
the network or proxy layer.
|
|
900
|
+
|
|
806
901
|
## License
|
|
807
902
|
|
|
808
903
|
MIT
|