dj-queue 0.6.2__tar.gz → 0.6.3__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 (70) hide show
  1. {dj_queue-0.6.2 → dj_queue-0.6.3}/PKG-INFO +1 -1
  2. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/admin.py +44 -1
  3. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/jobs.py +39 -2
  4. {dj_queue-0.6.2 → dj_queue-0.6.3}/pyproject.toml +1 -1
  5. {dj_queue-0.6.2 → dj_queue-0.6.3}/LICENSE +0 -0
  6. {dj_queue-0.6.2 → dj_queue-0.6.3}/README.md +0 -0
  7. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/__init__.py +0 -0
  8. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/api.py +0 -0
  9. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/apps.py +0 -0
  10. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/backend.py +0 -0
  11. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/config.py +0 -0
  12. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/contrib/__init__.py +0 -0
  13. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/contrib/asgi.py +0 -0
  14. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/contrib/gunicorn.py +0 -0
  15. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/contrib/prometheus.py +0 -0
  16. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/dashboard.py +0 -0
  17. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/db.py +0 -0
  18. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/exceptions.py +0 -0
  19. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/hooks.py +0 -0
  20. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/log.py +0 -0
  21. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/management/__init__.py +0 -0
  22. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/management/commands/__init__.py +0 -0
  23. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/management/commands/dj_queue.py +0 -0
  24. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/management/commands/dj_queue_health.py +0 -0
  25. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/management/commands/dj_queue_prune.py +0 -0
  26. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/0001_initial.py +0 -0
  27. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/0002_pause_semaphore.py +0 -0
  28. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/0003_recurringtask_recurringexecution.py +0 -0
  29. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/0004_dashboard.py +0 -0
  30. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/0005_remove_recurringexecution_dj_queue_recurring_executions_task_key_run_at_unique_and_more.py +0 -0
  31. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/migrations/__init__.py +0 -0
  32. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/models/__init__.py +0 -0
  33. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/models/jobs.py +0 -0
  34. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/models/recurring.py +0 -0
  35. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/models/runtime.py +0 -0
  36. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/observability.py +0 -0
  37. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/__init__.py +0 -0
  38. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/_insert.py +0 -0
  39. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/cleanup.py +0 -0
  40. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/concurrency.py +0 -0
  41. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/operations/recurring.py +0 -0
  42. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/routers.py +0 -0
  43. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/__init__.py +0 -0
  44. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/base.py +0 -0
  45. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/dispatcher.py +0 -0
  46. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/errors.py +0 -0
  47. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/interruptible.py +0 -0
  48. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/notify.py +0 -0
  49. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/pidfile.py +0 -0
  50. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/pool.py +0 -0
  51. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/procline.py +0 -0
  52. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/scheduler.py +0 -0
  53. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/supervisor.py +0 -0
  54. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/runtime/worker.py +0 -0
  55. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_dashboard_process_rows.html +0 -0
  56. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_dashboard_recurring_rows.html +0 -0
  57. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_dashboard_section_table.html +0 -0
  58. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_dashboard_semaphore_rows.html +0 -0
  59. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_paginator.html +0 -0
  60. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_queue_controls.html +0 -0
  61. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/_sortable_header_cells.html +0 -0
  62. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/change_form.html +0 -0
  63. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/change_list.html +0 -0
  64. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/dashboard.html +0 -0
  65. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/includes/fieldset.html +0 -0
  66. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templates/admin/dj_queue/queue_jobs.html +0 -0
  67. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templatetags/__init__.py +0 -0
  68. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/templatetags/dj_queue_admin.py +0 -0
  69. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/urls.py +0 -0
  70. {dj_queue-0.6.2 → dj_queue-0.6.3}/dj_queue/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dj-queue
3
- Version: 0.6.2
3
+ Version: 0.6.3
4
4
  Summary: Database-backed task queue backend for Django’s Tasks framework.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -28,7 +28,7 @@ from dj_queue.models import (
28
28
  RecurringTask,
29
29
  Semaphore,
30
30
  )
31
- from dj_queue.operations.jobs import enqueue_job_again
31
+ from dj_queue.operations.jobs import dispatch_scheduled_job_now, enqueue_job_again
32
32
 
33
33
 
34
34
  class DjQueueFirstAdminSite(admin.AdminSite):
@@ -563,6 +563,16 @@ class JobAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
563
563
  def get_change_actions(self, request, obj):
564
564
  if obj is None:
565
565
  return ()
566
+ if obj.status == "scheduled":
567
+ return (
568
+ {"name": "run_now", "label": "Run now", "css_class": "djq-object-action-retry"},
569
+ {
570
+ "name": "enqueue_copy_now",
571
+ "label": "Enqueue copy now",
572
+ "css_class": "djq-object-action-retry",
573
+ },
574
+ )
575
+
566
576
  actions = [{"name": "enqueue", "label": "Enqueue job", "css_class": "djq-object-action-retry"}]
567
577
  if obj.status == "failed":
568
578
  actions.extend(
@@ -582,6 +592,39 @@ class JobAdmin(HiddenSidebarAdminMixin, admin.ModelAdmin):
582
592
  return tuple(actions)
583
593
 
584
594
  def handle_change_action(self, request, obj, action):
595
+ if action == "run_now":
596
+ try:
597
+ _job, dispatched_as = dispatch_scheduled_job_now(obj.pk, backend_alias=obj.backend_alias)
598
+ except (EnqueueError, ImportError, AttributeError) as exc:
599
+ self.message_user(request, f"Could not dispatch job now: {exc}", level=messages.ERROR)
600
+ return self._current_object_redirect(obj, backend_alias=obj.backend_alias)
601
+
602
+ message = "Dispatched scheduled job for immediate execution"
603
+ if dispatched_as == "blocked":
604
+ message = "Dispatched scheduled job immediately and it is now blocked"
605
+ if dispatched_as == "discarded":
606
+ message = "Dispatched scheduled job immediately and it was discarded"
607
+ self.message_user(request, message, level=messages.SUCCESS)
608
+ return self._current_object_redirect(obj, backend_alias=obj.backend_alias)
609
+
610
+ if action == "enqueue_copy_now":
611
+ try:
612
+ new_job = enqueue_job_again(obj.pk, backend_alias=obj.backend_alias, run_after=None)
613
+ except (EnqueueError, ImportError, AttributeError) as exc:
614
+ self.message_user(request, f"Could not enqueue job: {exc}", level=messages.ERROR)
615
+ return self._current_object_redirect(obj, backend_alias=obj.backend_alias)
616
+
617
+ self.message_user(
618
+ request,
619
+ format_html(
620
+ 'Enqueued immediate copy <a href="{}">{}</a>.',
621
+ self._change_url(object_id=new_job.pk, backend_alias=new_job.backend_alias),
622
+ new_job.pk,
623
+ ),
624
+ level=messages.SUCCESS,
625
+ )
626
+ return self._current_object_redirect(obj, backend_alias=obj.backend_alias)
627
+
585
628
  if action == "enqueue":
586
629
  try:
587
630
  new_job = enqueue_job_again(obj.pk, backend_alias=obj.backend_alias)
@@ -351,6 +351,39 @@ def promote_scheduled_jobs(*, batch_size, backend_alias="default", use_skip_lock
351
351
  return jobs
352
352
 
353
353
 
354
+ def dispatch_scheduled_job_now(job_id, *, backend_alias="default"):
355
+ alias = get_database_alias(backend_alias)
356
+ config = load_backend_config(backend_alias)
357
+
358
+ with transaction.atomic(using=alias):
359
+ scheduled = locked_queryset(
360
+ ScheduledExecution.objects.using(alias)
361
+ .select_related("job")
362
+ .filter(job_id=job_id, job__backend_alias=backend_alias),
363
+ use_skip_locked=config.use_skip_locked,
364
+ ).first()
365
+ if scheduled is None:
366
+ raise EnqueueError("job is not scheduled")
367
+
368
+ job = scheduled.job
369
+ scheduled.delete(using=alias)
370
+ job.scheduled_at = None
371
+ job.save(using=alias, update_fields=["scheduled_at", "updated_at"])
372
+ dispatched_as = _dispatch_existing_job(job)
373
+
374
+ if dispatched_as == "ready":
375
+ runtime_notify.notify_ready_queues((job.queue_name,), backend_alias=backend_alias)
376
+
377
+ log_event(
378
+ "job.dispatched_now",
379
+ job_id=str(job.id),
380
+ queue_name=job.queue_name,
381
+ priority=job.priority,
382
+ dispatched_as=dispatched_as,
383
+ )
384
+ return job, dispatched_as
385
+
386
+
354
387
  def retry_failed_job(job_id, *, backend_alias="default"):
355
388
  alias = get_database_alias(backend_alias)
356
389
 
@@ -370,15 +403,19 @@ def retry_failed_job(job_id, *, backend_alias="default"):
370
403
  return job
371
404
 
372
405
 
373
- def enqueue_job_again(job_id, *, backend_alias="default"):
406
+ _KEEP_RUN_AFTER = object()
407
+
408
+
409
+ def enqueue_job_again(job_id, *, backend_alias="default", run_after=_KEEP_RUN_AFTER):
374
410
  alias = get_database_alias(backend_alias)
375
411
  source_job = Job.objects.using(alias).get(pk=job_id)
376
412
  task = import_string(source_job.task_path)
413
+ source_run_after = source_job.scheduled_at if run_after is _KEEP_RUN_AFTER else run_after
377
414
  if hasattr(task, "using"):
378
415
  task = task.using(
379
416
  priority=source_job.priority,
380
417
  queue_name=source_job.queue_name,
381
- run_after=source_job.scheduled_at,
418
+ run_after=source_run_after,
382
419
  backend=source_job.backend_alias,
383
420
  )
384
421
  args = list(source_job.payload.get("args", []))
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "dj-queue"
7
- version = "0.6.2"
7
+ version = "0.6.3"
8
8
  description = "Database-backed task queue backend for Django’s Tasks framework."
9
9
  readme = "README.md"
10
10
  license = "MIT"
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
File without changes
File without changes
File without changes