dj-queue 0.10.0__tar.gz → 0.10.2__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.
Files changed (86) hide show
  1. {dj_queue-0.10.0 → dj_queue-0.10.2}/PKG-INFO +9 -1
  2. {dj_queue-0.10.0 → dj_queue-0.10.2}/README.md +8 -0
  3. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/config.py +15 -2
  4. dj_queue-0.10.2/dj_queue/management/commands/dj_queue.py +106 -0
  5. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/jobs.py +2 -2
  6. {dj_queue-0.10.0 → dj_queue-0.10.2}/pyproject.toml +1 -1
  7. dj_queue-0.10.0/dj_queue/management/commands/dj_queue.py +0 -44
  8. {dj_queue-0.10.0 → dj_queue-0.10.2}/LICENSE +0 -0
  9. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/__init__.py +0 -0
  10. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/admin.py +0 -0
  11. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/api.py +0 -0
  12. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/apps.py +0 -0
  13. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/backend.py +0 -0
  14. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/contrib/__init__.py +0 -0
  15. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/contrib/asgi.py +0 -0
  16. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/contrib/gunicorn.py +0 -0
  17. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/contrib/prometheus.py +0 -0
  18. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/cron.py +0 -0
  19. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/dashboard.py +0 -0
  20. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/db.py +0 -0
  21. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/exceptions.py +0 -0
  22. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/hooks.py +0 -0
  23. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/log.py +0 -0
  24. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/management/__init__.py +0 -0
  25. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/management/commands/__init__.py +0 -0
  26. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/management/commands/dj_queue_health.py +0 -0
  27. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/management/commands/dj_queue_prune.py +0 -0
  28. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/metrics.py +0 -0
  29. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0001_initial.py +0 -0
  30. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0002_pause_semaphore.py +0 -0
  31. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0003_recurringtask_recurringexecution.py +0 -0
  32. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0004_dashboard.py +0 -0
  33. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0005_remove_recurringexecution_dj_queue_recurring_executions_task_key_run_at_unique_and_more.py +0 -0
  34. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0006_blockedexecution_dj_queue_bl_concurr_2d8393_idx_and_more.py +0 -0
  35. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0007_recurringtask_next_run_at.py +0 -0
  36. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0008_remove_blockedexecution_dj_queue_bl_concurr_1ce730_idx_and_more.py +0 -0
  37. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0009_remove_process_dj_queue_processes_name_supervisor_unique_and_more.py +0 -0
  38. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/0010_remove_process_djq_pr_name_parent_uniq_and_more.py +0 -0
  39. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/migrations/__init__.py +0 -0
  40. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/models/__init__.py +0 -0
  41. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/models/jobs.py +0 -0
  42. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/models/recurring.py +0 -0
  43. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/models/runtime.py +0 -0
  44. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/observability.py +0 -0
  45. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/__init__.py +0 -0
  46. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/_helpers.py +0 -0
  47. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/_insert.py +0 -0
  48. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/cleanup.py +0 -0
  49. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/concurrency.py +0 -0
  50. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/queues.py +0 -0
  51. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/operations/recurring.py +0 -0
  52. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/queue_selectors.py +0 -0
  53. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/queue_state.py +0 -0
  54. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/routers.py +0 -0
  55. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/__init__.py +0 -0
  56. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/base.py +0 -0
  57. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/connection_budget.py +0 -0
  58. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/dispatcher.py +0 -0
  59. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/errors.py +0 -0
  60. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/interruptible.py +0 -0
  61. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/notify.py +0 -0
  62. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/pidfile.py +0 -0
  63. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/pool.py +0 -0
  64. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/procline.py +0 -0
  65. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/scheduler.py +0 -0
  66. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/supervisor.py +0 -0
  67. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/topology.py +0 -0
  68. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/runtime/worker.py +0 -0
  69. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/task_results.py +0 -0
  70. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_dashboard_process_rows.html +0 -0
  71. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_dashboard_recurring_rows.html +0 -0
  72. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_dashboard_section_table.html +0 -0
  73. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_dashboard_semaphore_rows.html +0 -0
  74. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_paginator.html +0 -0
  75. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_queue_controls.html +0 -0
  76. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/_sortable_header_cells.html +0 -0
  77. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/change_form.html +0 -0
  78. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/change_list.html +0 -0
  79. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/dashboard.html +1 -1
  80. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/includes/fieldset.html +0 -0
  81. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templates/admin/dj_queue/queue_jobs.html +0 -0
  82. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templatetags/__init__.py +0 -0
  83. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/templatetags/dj_queue_admin.py +0 -0
  84. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/urls.py +0 -0
  85. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/views.py +0 -0
  86. {dj_queue-0.10.0 → dj_queue-0.10.2}/dj_queue/wakeup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dj-queue
3
- Version: 0.10.0
3
+ Version: 0.10.2
4
4
  Summary: Database-backed task queue backend for Django’s Tasks framework.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -115,6 +115,11 @@ Run migrations:
115
115
  python manage.py migrate
116
116
  ```
117
117
 
118
+ `python manage.py dj_queue` checks for pending `dj_queue` migrations before it
119
+ starts workers. If another process is applying migrations during startup, the
120
+ runtime waits up to 60 seconds by default instead of starting against a stale
121
+ queue schema.
122
+
118
123
  ## Quick Start
119
124
 
120
125
  Define a task with Django's `@task` decorator:
@@ -274,11 +279,14 @@ python manage.py dj_queue --backend <alias>
274
279
  python manage.py dj_queue --only-work
275
280
  python manage.py dj_queue --only-dispatch
276
281
  python manage.py dj_queue --skip-recurring
282
+ python manage.py dj_queue --migration-wait-timeout 120
277
283
  ```
278
284
 
279
285
  Notes:
280
286
 
281
287
  - `fork` is the default standalone mode
288
+ - startup waits up to 60 seconds for pending `dj_queue` migrations to finish;
289
+ use `--migration-wait-timeout 0` to fail fast instead
282
290
  - `async` is also supported as a standalone mode and runs supervised actors in threads inside one process
283
291
  - `--backend` targets a non-default backend alias
284
292
  - `--only-work` starts workers without dispatchers or scheduler
@@ -89,6 +89,11 @@ Run migrations:
89
89
  python manage.py migrate
90
90
  ```
91
91
 
92
+ `python manage.py dj_queue` checks for pending `dj_queue` migrations before it
93
+ starts workers. If another process is applying migrations during startup, the
94
+ runtime waits up to 60 seconds by default instead of starting against a stale
95
+ queue schema.
96
+
92
97
  ## Quick Start
93
98
 
94
99
  Define a task with Django's `@task` decorator:
@@ -248,11 +253,14 @@ python manage.py dj_queue --backend <alias>
248
253
  python manage.py dj_queue --only-work
249
254
  python manage.py dj_queue --only-dispatch
250
255
  python manage.py dj_queue --skip-recurring
256
+ python manage.py dj_queue --migration-wait-timeout 120
251
257
  ```
252
258
 
253
259
  Notes:
254
260
 
255
261
  - `fork` is the default standalone mode
262
+ - startup waits up to 60 seconds for pending `dj_queue` migrations to finish;
263
+ use `--migration-wait-timeout 0` to fail fast instead
256
264
  - `async` is also supported as a standalone mode and runs supervised actors in threads inside one process
257
265
  - `--backend` targets a non-default backend alias
258
266
  - `--only-work` starts workers without dispatchers or scheduler
@@ -166,6 +166,18 @@ def load_backend_config(
166
166
  return _BACKEND_CONFIG_CACHE[cache_key]
167
167
 
168
168
 
169
+ def load_allowed_queues(
170
+ backend_alias: str = "default",
171
+ *,
172
+ tasks_settings: Mapping[str, Any] | None = None,
173
+ ) -> tuple[str, ...]:
174
+ if tasks_settings is None:
175
+ tasks_settings = getattr(settings, "TASKS", {})
176
+ ensure_dj_queue_backend_alias(tasks_settings, backend_alias)
177
+ backend_block = _backend_block(tasks_settings, backend_alias)
178
+ return _as_string_tuple(backend_block.get("QUEUES", []))
179
+
180
+
169
181
  def _load_backend_config_uncached(
170
182
  backend_alias: str,
171
183
  cli_overrides: Mapping[str, Any],
@@ -189,10 +201,11 @@ def _load_backend_config_uncached(
189
201
  preserve_finished_jobs = _bool_option(
190
202
  resolved_options["preserve_finished_jobs"], "preserve_finished_jobs"
191
203
  )
204
+ allowed_queues = _as_string_tuple(backend_block.get("QUEUES", []))
192
205
  on_thread_error = _validated_callback_path(resolved_options.get("on_thread_error"))
193
206
  recurring = _build_recurring_config(
194
207
  resolved_options.get("recurring", {}),
195
- allowed_queues=_as_string_tuple(backend_block.get("QUEUES", [])),
208
+ allowed_queues=allowed_queues,
196
209
  backend_alias=backend_alias,
197
210
  )
198
211
  scheduler = _build_scheduler_config(resolved_options.get("scheduler", DEFAULT_SCHEDULER))
@@ -222,7 +235,7 @@ def _load_backend_config_uncached(
222
235
 
223
236
  return BackendConfig(
224
237
  backend_alias=backend_alias,
225
- allowed_queues=_as_string_tuple(backend_block.get("QUEUES", [])),
238
+ allowed_queues=allowed_queues,
226
239
  mode=mode,
227
240
  workers=workers,
228
241
  dispatchers=dispatchers,
@@ -0,0 +1,106 @@
1
+ import math
2
+ import time
3
+
4
+ from django.core.exceptions import ImproperlyConfigured
5
+ from django.core.management.base import BaseCommand
6
+ from django.core.management.base import CommandError
7
+ from django.db import connections
8
+ from django.db.migrations.executor import MigrationExecutor
9
+
10
+ from dj_queue.config import load_backend_config
11
+ from dj_queue.runtime.supervisor import AsyncSupervisor, ForkSupervisor
12
+
13
+ MIGRATION_WAIT_TIMEOUT = 60
14
+ MIGRATION_WAIT_INTERVAL = 0.5
15
+
16
+
17
+ def build_supervisor(*, backend_alias, cli_overrides):
18
+ mode = load_backend_config(backend_alias, cli_overrides=cli_overrides).mode
19
+ supervisor_class = AsyncSupervisor if mode == "async" else ForkSupervisor
20
+ return supervisor_class.from_backend_config(
21
+ backend_alias=backend_alias,
22
+ cli_overrides=cli_overrides,
23
+ )
24
+
25
+
26
+ def wait_for_dj_queue_migrations(
27
+ database_alias,
28
+ *,
29
+ timeout=MIGRATION_WAIT_TIMEOUT,
30
+ interval=MIGRATION_WAIT_INTERVAL,
31
+ stdout=None,
32
+ ):
33
+ if not math.isfinite(timeout) or timeout < 0:
34
+ raise CommandError("dj_queue migration wait timeout must be non-negative")
35
+
36
+ deadline = time.monotonic() + timeout
37
+ announced = False
38
+ while True:
39
+ pending = pending_dj_queue_migrations(database_alias)
40
+ if not pending:
41
+ return
42
+
43
+ migration_names = ", ".join(
44
+ f"{migration.app_label}.{migration.name}" for migration, _backwards in pending
45
+ )
46
+ if stdout is not None and not announced:
47
+ stdout.write(
48
+ f"waiting for dj_queue migrations on database {database_alias!r}: {migration_names}"
49
+ )
50
+ announced = True
51
+
52
+ if time.monotonic() >= deadline:
53
+ raise CommandError(
54
+ f"dj_queue migrations are pending on database {database_alias!r}: {migration_names}; "
55
+ f"run manage.py migrate dj_queue --database {database_alias} before starting dj_queue"
56
+ )
57
+ time.sleep(min(interval, max(deadline - time.monotonic(), 0)))
58
+
59
+
60
+ def pending_dj_queue_migrations(database_alias):
61
+ executor = MigrationExecutor(connections[database_alias])
62
+ targets = [node for node in executor.loader.graph.leaf_nodes() if node[0] == "dj_queue"]
63
+ return [
64
+ (migration, backwards)
65
+ for migration, backwards in executor.migration_plan(targets)
66
+ if migration.app_label == "dj_queue"
67
+ ]
68
+
69
+
70
+ class Command(BaseCommand):
71
+ help = "Start the dj_queue supervisor"
72
+
73
+ def add_arguments(self, parser):
74
+ parser.add_argument("--backend", default="default")
75
+ parser.add_argument("--config")
76
+ parser.add_argument("--mode", choices=("fork", "async"))
77
+ parser.add_argument("--only-work", action="store_true")
78
+ parser.add_argument("--only-dispatch", action="store_true")
79
+ parser.add_argument("--skip-recurring", action="store_true")
80
+ parser.add_argument("--migration-wait-timeout", type=float, default=MIGRATION_WAIT_TIMEOUT)
81
+
82
+ def handle(self, *args, **options):
83
+ cli_overrides = {
84
+ "config": options["config"],
85
+ "mode": options["mode"],
86
+ "only_work": options["only_work"],
87
+ "only_dispatch": options["only_dispatch"],
88
+ "skip_recurring": options["skip_recurring"],
89
+ }
90
+ try:
91
+ config = load_backend_config(
92
+ options["backend"],
93
+ cli_overrides=cli_overrides,
94
+ )
95
+ wait_for_dj_queue_migrations(
96
+ config.database_alias,
97
+ timeout=options["migration_wait_timeout"],
98
+ stdout=self.stdout,
99
+ )
100
+ supervisor = build_supervisor(
101
+ backend_alias=options["backend"],
102
+ cli_overrides=cli_overrides,
103
+ )
104
+ except ImproperlyConfigured as exc:
105
+ raise CommandError(str(exc)) from exc
106
+ supervisor.run()
@@ -14,7 +14,7 @@ from django.tasks import TaskContext
14
14
  from django.utils import timezone
15
15
  from django.utils.module_loading import import_string
16
16
 
17
- from dj_queue.config import load_backend_config
17
+ from dj_queue.config import load_allowed_queues, load_backend_config
18
18
  from dj_queue.db import get_database_alias, locked_queryset
19
19
  from dj_queue.exceptions import EnqueueError
20
20
  from dj_queue.log import event_logging_enabled, log_event
@@ -1006,7 +1006,7 @@ def _semaphore_limit(job):
1006
1006
 
1007
1007
 
1008
1008
  def validate_queue_allowed(queue_name, *, backend_alias="default"):
1009
- allowed_queues = load_backend_config(backend_alias).allowed_queues
1009
+ allowed_queues = load_allowed_queues(backend_alias)
1010
1010
  if allowed_queues and queue_name not in allowed_queues:
1011
1011
  raise EnqueueError(f"queue {queue_name!r} is not allowed for backend {backend_alias!r}")
1012
1012
 
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "dj-queue"
7
- version = "0.10.0"
7
+ version = "0.10.2"
8
8
  description = "Database-backed task queue backend for Django’s Tasks framework."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,44 +0,0 @@
1
- from django.core.exceptions import ImproperlyConfigured
2
- from django.core.management.base import BaseCommand
3
- from django.core.management.base import CommandError
4
-
5
- from dj_queue.config import load_backend_config
6
- from dj_queue.runtime.supervisor import AsyncSupervisor, ForkSupervisor
7
-
8
-
9
- def build_supervisor(*, backend_alias, cli_overrides):
10
- mode = load_backend_config(backend_alias, cli_overrides=cli_overrides).mode
11
- supervisor_class = AsyncSupervisor if mode == "async" else ForkSupervisor
12
- return supervisor_class.from_backend_config(
13
- backend_alias=backend_alias,
14
- cli_overrides=cli_overrides,
15
- )
16
-
17
-
18
- class Command(BaseCommand):
19
- help = "Start the dj_queue supervisor"
20
-
21
- def add_arguments(self, parser):
22
- parser.add_argument("--backend", default="default")
23
- parser.add_argument("--config")
24
- parser.add_argument("--mode", choices=("fork", "async"))
25
- parser.add_argument("--only-work", action="store_true")
26
- parser.add_argument("--only-dispatch", action="store_true")
27
- parser.add_argument("--skip-recurring", action="store_true")
28
-
29
- def handle(self, *args, **options):
30
- cli_overrides = {
31
- "config": options["config"],
32
- "mode": options["mode"],
33
- "only_work": options["only_work"],
34
- "only_dispatch": options["only_dispatch"],
35
- "skip_recurring": options["skip_recurring"],
36
- }
37
- try:
38
- supervisor = build_supervisor(
39
- backend_alias=options["backend"],
40
- cli_overrides=cli_overrides,
41
- )
42
- except ImproperlyConfigured as exc:
43
- raise CommandError(str(exc)) from exc
44
- supervisor.run()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -586,8 +586,8 @@
586
586
  <tr class="{% cycle 'row1' 'row2' %}">
587
587
  <th class="djq-col-name"><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=ready">{{ queue.name }}</a></th>
588
588
  <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=ready">{{ queue.ready_count }}</a></td>
589
- <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=claimed">{{ queue.claimed_count }}</a></td>
590
589
  <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=scheduled">{{ queue.scheduled_count }}</a></td>
590
+ <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=claimed">{{ queue.claimed_count }}</a></td>
591
591
  <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=blocked">{{ queue.blocked_count }}</a></td>
592
592
  <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=failed">{{ queue.failed_count }}</a></td>
593
593
  <td><a href="{% url 'admin:dj_queue_dashboard_queue' queue.name %}?backend={{ backend_alias }}&state=finished">{{ queue.finished_count }}</a></td>
File without changes
File without changes
File without changes