django-database-task 0.2.0__tar.gz → 0.2.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 (37) hide show
  1. {django_database_task-0.2.0/django_database_task.egg-info → django_database_task-0.2.2}/PKG-INFO +69 -17
  2. {django_database_task-0.2.0 → django_database_task-0.2.2}/README.md +68 -16
  3. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/__init__.py +1 -1
  4. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/backends.py +10 -6
  5. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/backend.py +14 -10
  6. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/detection.py +42 -5
  7. {django_database_task-0.2.0 → django_database_task-0.2.2/django_database_task.egg-info}/PKG-INFO +69 -17
  8. {django_database_task-0.2.0 → django_database_task-0.2.2}/pyproject.toml +1 -1
  9. {django_database_task-0.2.0 → django_database_task-0.2.2}/LICENSE +0 -0
  10. {django_database_task-0.2.0 → django_database_task-0.2.2}/MANIFEST.in +0 -0
  11. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/admin.py +0 -0
  12. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/apps.py +0 -0
  13. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/__init__.py +0 -0
  14. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/auth.py +0 -0
  15. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/executor.py +0 -0
  16. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/locale/ja/LC_MESSAGES/django.mo +0 -0
  17. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/locale/ja/LC_MESSAGES/django.po +0 -0
  18. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/__init__.py +0 -0
  19. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/__init__.py +0 -0
  20. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/purge_completed_database_tasks.py +0 -0
  21. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/run_database_tasks.py +0 -0
  22. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/migrations/0001_initial.py +0 -0
  23. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/migrations/__init__.py +0 -0
  24. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/models.py +0 -0
  25. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/urls.py +0 -0
  26. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/views.py +0 -0
  27. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/SOURCES.txt +0 -0
  28. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/dependency_links.txt +0 -0
  29. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/requires.txt +0 -0
  30. {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/top_level.txt +0 -0
  31. {django_database_task-0.2.0 → django_database_task-0.2.2}/setup.cfg +0 -0
  32. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_admin.py +0 -0
  33. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_backend.py +0 -0
  34. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_commands.py +0 -0
  35. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_executor.py +0 -0
  36. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_models.py +0 -0
  37. {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-database-task
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A database-backed task queue backend for Django 6.0's built-in task framework
5
5
  Author-email: Shinya Okano <tokibito@gmail.com>
6
6
  Maintainer-email: Shinya Okano <tokibito@gmail.com>
@@ -36,6 +36,11 @@ Dynamic: license-file
36
36
 
37
37
  # django-database-task
38
38
 
39
+ [![CI](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml/badge.svg)](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
40
+ [![PyPI version](https://badge.fury.io/py/django-database-task.svg)](https://badge.fury.io/py/django-database-task)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-database-task.svg)](https://pypi.org/project/django-database-task/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
+
39
44
  A database-backed task queue backend for Django 6.0's built-in task framework.
40
45
 
41
46
  ## Features
@@ -607,21 +612,68 @@ pip install django-database-task[cloudtasks]
607
612
  TASKS = {
608
613
  "default": {
609
614
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
610
- "OPTIONS": {
611
- "CLOUD_TASKS_QUEUE": "default", # Only required setting
612
- },
615
+ "QUEUES": [], # Allow all queue names
613
616
  },
614
617
  }
615
618
  ```
616
619
 
617
- Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment variables.
620
+ Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
618
621
 
619
- ### How It Works
622
+ **Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
623
+ ```python
624
+ "QUEUES": ["default", "emails", "batch"], # Only these queues allowed
625
+ ```
626
+
627
+ The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
628
+
629
+ ```python
630
+ @task # Uses "default" queue
631
+ def normal_task():
632
+ pass
633
+
634
+ @task(queue="batch") # Uses "batch" queue
635
+ def batch_task():
636
+ pass
620
637
 
638
+ @task(queue="high-priority") # Uses "high-priority" queue
639
+ def urgent_task():
640
+ pass
621
641
  ```
622
- 1. App enqueues task → Task saved to database + Cloud Task created
623
- 2. Cloud Task triggers HTTP request /tasks/execute/<task_id>/
624
- 3. Handler retrieves task from database and executes it
642
+
643
+ This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
644
+
645
+ ### How It Works
646
+
647
+ ```mermaid
648
+ sequenceDiagram
649
+ participant App as Application
650
+ participant Backend as CloudTasksDatabaseBackend
651
+ participant DB as Database
652
+ participant CT as Cloud Tasks
653
+ participant Handler as /tasks/execute/
654
+
655
+ Note over App,Handler: Task Enqueue
656
+ App->>Backend: task.enqueue(args, kwargs)
657
+ Backend->>DB: INSERT task (status=READY)
658
+ DB-->>Backend: Task ID
659
+ Backend->>CT: Create Cloud Task (task_id only)
660
+ CT-->>Backend: OK
661
+ Backend-->>App: TaskResult (id, status=READY)
662
+
663
+ Note over App,Handler: Task Execution (triggered by Cloud Tasks)
664
+ CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
665
+ Handler->>Handler: Verify OIDC token (optional)
666
+ Handler->>DB: SELECT task by ID
667
+ DB-->>Handler: Task record
668
+ Handler->>DB: UPDATE status=RUNNING
669
+ Handler->>Handler: Execute task function
670
+ alt Success
671
+ Handler->>DB: UPDATE status=SUCCESSFUL
672
+ Handler-->>CT: HTTP 200
673
+ else Failure
674
+ Handler->>DB: UPDATE status=FAILED
675
+ Handler-->>CT: HTTP 500 (triggers retry)
676
+ end
625
677
  ```
626
678
 
627
679
  The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
@@ -636,10 +688,9 @@ TASKS = {
636
688
  "default": {
637
689
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
638
690
  "OPTIONS": {
639
- # Required
640
- "CLOUD_TASKS_QUEUE": "default",
691
+ # All settings are optional - auto-detected from environment
641
692
 
642
- # Auto-detected (override if needed)
693
+ # Override auto-detection if needed
643
694
  # "CLOUD_TASKS_PROJECT": "my-project",
644
695
  # "CLOUD_TASKS_LOCATION": "asia-northeast1",
645
696
  # "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
@@ -655,11 +706,12 @@ TASKS = {
655
706
 
656
707
  ### Auto-Detection
657
708
 
658
- | Setting | Environment Variable | Description |
659
- |---------|---------------------|-------------|
660
- | Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
661
- | Location | `CLOUD_RUN_REGION` / `GAE_REGION` | Cloud Tasks region |
709
+ | Setting | Detection Method | Description |
710
+ |---------|------------------|-------------|
711
+ | Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
712
+ | Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
662
713
  | Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
714
+ | Queue name | Task's `queue_name` attribute | Defaults to "default" |
663
715
 
664
716
  ### OIDC Authentication
665
717
 
@@ -670,8 +722,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
670
722
  TASKS = {
671
723
  "default": {
672
724
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
725
+ "QUEUES": [], # Allow all queue names
673
726
  "OPTIONS": {
674
- "CLOUD_TASKS_QUEUE": "default",
675
727
  "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
676
728
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
677
729
  },
@@ -1,5 +1,10 @@
1
1
  # django-database-task
2
2
 
3
+ [![CI](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml/badge.svg)](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
4
+ [![PyPI version](https://badge.fury.io/py/django-database-task.svg)](https://badge.fury.io/py/django-database-task)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-database-task.svg)](https://pypi.org/project/django-database-task/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
3
8
  A database-backed task queue backend for Django 6.0's built-in task framework.
4
9
 
5
10
  ## Features
@@ -571,21 +576,68 @@ pip install django-database-task[cloudtasks]
571
576
  TASKS = {
572
577
  "default": {
573
578
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
574
- "OPTIONS": {
575
- "CLOUD_TASKS_QUEUE": "default", # Only required setting
576
- },
579
+ "QUEUES": [], # Allow all queue names
577
580
  },
578
581
  }
579
582
  ```
580
583
 
581
- Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment variables.
584
+ Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
582
585
 
583
- ### How It Works
586
+ **Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
587
+ ```python
588
+ "QUEUES": ["default", "emails", "batch"], # Only these queues allowed
589
+ ```
590
+
591
+ The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
592
+
593
+ ```python
594
+ @task # Uses "default" queue
595
+ def normal_task():
596
+ pass
597
+
598
+ @task(queue="batch") # Uses "batch" queue
599
+ def batch_task():
600
+ pass
584
601
 
602
+ @task(queue="high-priority") # Uses "high-priority" queue
603
+ def urgent_task():
604
+ pass
585
605
  ```
586
- 1. App enqueues task → Task saved to database + Cloud Task created
587
- 2. Cloud Task triggers HTTP request /tasks/execute/<task_id>/
588
- 3. Handler retrieves task from database and executes it
606
+
607
+ This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
608
+
609
+ ### How It Works
610
+
611
+ ```mermaid
612
+ sequenceDiagram
613
+ participant App as Application
614
+ participant Backend as CloudTasksDatabaseBackend
615
+ participant DB as Database
616
+ participant CT as Cloud Tasks
617
+ participant Handler as /tasks/execute/
618
+
619
+ Note over App,Handler: Task Enqueue
620
+ App->>Backend: task.enqueue(args, kwargs)
621
+ Backend->>DB: INSERT task (status=READY)
622
+ DB-->>Backend: Task ID
623
+ Backend->>CT: Create Cloud Task (task_id only)
624
+ CT-->>Backend: OK
625
+ Backend-->>App: TaskResult (id, status=READY)
626
+
627
+ Note over App,Handler: Task Execution (triggered by Cloud Tasks)
628
+ CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
629
+ Handler->>Handler: Verify OIDC token (optional)
630
+ Handler->>DB: SELECT task by ID
631
+ DB-->>Handler: Task record
632
+ Handler->>DB: UPDATE status=RUNNING
633
+ Handler->>Handler: Execute task function
634
+ alt Success
635
+ Handler->>DB: UPDATE status=SUCCESSFUL
636
+ Handler-->>CT: HTTP 200
637
+ else Failure
638
+ Handler->>DB: UPDATE status=FAILED
639
+ Handler-->>CT: HTTP 500 (triggers retry)
640
+ end
589
641
  ```
590
642
 
591
643
  The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
@@ -600,10 +652,9 @@ TASKS = {
600
652
  "default": {
601
653
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
602
654
  "OPTIONS": {
603
- # Required
604
- "CLOUD_TASKS_QUEUE": "default",
655
+ # All settings are optional - auto-detected from environment
605
656
 
606
- # Auto-detected (override if needed)
657
+ # Override auto-detection if needed
607
658
  # "CLOUD_TASKS_PROJECT": "my-project",
608
659
  # "CLOUD_TASKS_LOCATION": "asia-northeast1",
609
660
  # "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
@@ -619,11 +670,12 @@ TASKS = {
619
670
 
620
671
  ### Auto-Detection
621
672
 
622
- | Setting | Environment Variable | Description |
623
- |---------|---------------------|-------------|
624
- | Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
625
- | Location | `CLOUD_RUN_REGION` / `GAE_REGION` | Cloud Tasks region |
673
+ | Setting | Detection Method | Description |
674
+ |---------|------------------|-------------|
675
+ | Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
676
+ | Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
626
677
  | Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
678
+ | Queue name | Task's `queue_name` attribute | Defaults to "default" |
627
679
 
628
680
  ### OIDC Authentication
629
681
 
@@ -634,8 +686,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
634
686
  TASKS = {
635
687
  "default": {
636
688
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
689
+ "QUEUES": [], # Allow all queue names
637
690
  "OPTIONS": {
638
- "CLOUD_TASKS_QUEUE": "default",
639
691
  "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
640
692
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
641
693
  },
@@ -2,7 +2,7 @@
2
2
  django-database-task: A database-backed task queue backend for Django 6.0's task framework.
3
3
  """
4
4
 
5
- __version__ = "0.2.0"
5
+ __version__ = "0.2.2"
6
6
 
7
7
 
8
8
  def __getattr__(name):
@@ -169,15 +169,19 @@ class DatabaseTaskBackend(BaseTaskBackend):
169
169
  args = db_task.args_json
170
170
  kwargs = db_task.kwargs_json.copy()
171
171
 
172
+ # Execute task
173
+ # If takes_context, pass TaskContext as first positional argument
172
174
  if takes_context:
173
175
  context = TaskContext(task_result=task_result)
174
- kwargs["context"] = context
175
-
176
- # Execute task
177
- if iscoroutinefunction(func):
178
- return_value = asyncio.run(func(*args, **kwargs))
176
+ if iscoroutinefunction(func):
177
+ return_value = asyncio.run(func(context, *args, **kwargs))
178
+ else:
179
+ return_value = func(context, *args, **kwargs)
179
180
  else:
180
- return_value = func(*args, **kwargs)
181
+ if iscoroutinefunction(func):
182
+ return_value = asyncio.run(func(*args, **kwargs))
183
+ else:
184
+ return_value = func(*args, **kwargs)
181
185
 
182
186
  # Normalize return value for JSON serialization
183
187
  # This will raise TypeError for unsupported types
@@ -37,11 +37,17 @@ class CloudTasksDatabaseBackend(DatabaseTaskBackend):
37
37
  TASKS = {
38
38
  "default": {
39
39
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
40
- "OPTIONS": {
41
- "CLOUD_TASKS_QUEUE": "default",
42
- },
43
40
  },
44
41
  }
42
+
43
+ The Cloud Tasks queue name is determined by the task's queue_name attribute.
44
+ For example:
45
+ @task(queue="high-priority")
46
+ def urgent_task():
47
+ ...
48
+ will use the "high-priority" Cloud Tasks queue.
49
+
50
+ Tasks without explicit queue use Django's DEFAULT_TASK_QUEUE_NAME ("default").
45
51
  """
46
52
 
47
53
  def __init__(self, alias, params):
@@ -49,11 +55,6 @@ class CloudTasksDatabaseBackend(DatabaseTaskBackend):
49
55
 
50
56
  options = params.get("OPTIONS", {})
51
57
 
52
- # Required: Queue name
53
- self.queue_name = options.get("CLOUD_TASKS_QUEUE")
54
- if not self.queue_name:
55
- raise ImproperlyConfigured("CLOUD_TASKS_QUEUE is required in TASKS OPTIONS")
56
-
57
58
  # Auto-detected or explicit: Project ID
58
59
  self.project = options.get("CLOUD_TASKS_PROJECT") or detect_gcp_project()
59
60
  if not self.project:
@@ -188,12 +189,15 @@ class CloudTasksDatabaseBackend(DatabaseTaskBackend):
188
189
 
189
190
  The Cloud Task only contains the task ID in the URL.
190
191
  Task parameters are retrieved from the database when executed.
192
+
193
+ The Cloud Tasks queue name is taken from the task's queue_name attribute.
191
194
  """
192
- # Build queue path
195
+ # Build queue path using task's queue_name
196
+ queue_name = task_result.task.queue_name
193
197
  parent = self.client.queue_path(
194
198
  self.project,
195
199
  self.location,
196
- self.queue_name,
200
+ queue_name,
197
201
  )
198
202
 
199
203
  # Build task handler URL (contains only task ID)
@@ -31,7 +31,7 @@ def detect_gcp_project():
31
31
 
32
32
  def detect_gcp_location():
33
33
  """
34
- Detect Cloud Tasks location (region) from environment variables.
34
+ Detect Cloud Tasks location (region) from environment variables or metadata server.
35
35
 
36
36
  Returns:
37
37
  Region string or None if not detected.
@@ -41,16 +41,53 @@ def detect_gcp_location():
41
41
  if region:
42
42
  return region
43
43
 
44
- # GAE: Check for region environment variables
45
- region = os.environ.get("GAE_REGION") or os.environ.get("GOOGLE_CLOUD_REGION")
44
+ # Explicit environment variable (works for any environment)
45
+ region = os.environ.get("GOOGLE_CLOUD_REGION")
46
+ if region:
47
+ return region
48
+
49
+ # GAE/GCE: Query metadata server for zone and extract region
50
+ region = _detect_region_from_metadata()
46
51
  if region:
47
52
  return region
48
53
 
49
- # Note: GAE may not provide region via environment variables
50
- # In that case, explicit configuration is required
51
54
  return None
52
55
 
53
56
 
57
+ def _detect_region_from_metadata():
58
+ """
59
+ Detect region from GCP metadata server.
60
+
61
+ The metadata server returns zone in format:
62
+ projects/PROJECT_NUMBER/zones/ZONE_NAME (e.g., projects/12345/zones/us-central1-a)
63
+
64
+ We extract the region by removing the zone suffix (e.g., us-central1).
65
+
66
+ Returns:
67
+ Region string or None if not available.
68
+ """
69
+ import urllib.error
70
+ import urllib.request
71
+
72
+ metadata_url = "http://metadata.google.internal/computeMetadata/v1/instance/zone"
73
+ headers = {"Metadata-Flavor": "Google"}
74
+
75
+ try:
76
+ request = urllib.request.Request(metadata_url, headers=headers)
77
+ with urllib.request.urlopen(request, timeout=2) as response:
78
+ # Response format: projects/PROJECT_NUMBER/zones/ZONE_NAME
79
+ zone_path = response.read().decode("utf-8")
80
+ # Extract zone name (last part)
81
+ zone = zone_path.split("/")[-1]
82
+ # Extract region by removing the last part (e.g., us-central1-a -> us-central1)
83
+ # Zone format: {region}-{zone_letter} (e.g., us-central1-a, asia-northeast1-b)
84
+ region = "-".join(zone.rsplit("-", 1)[:-1])
85
+ return region if region else None
86
+ except (urllib.error.URLError, OSError):
87
+ # Metadata server not available (local development, etc.)
88
+ return None
89
+
90
+
54
91
  def detect_default_service_account():
55
92
  """
56
93
  Detect the default service account email.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-database-task
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: A database-backed task queue backend for Django 6.0's built-in task framework
5
5
  Author-email: Shinya Okano <tokibito@gmail.com>
6
6
  Maintainer-email: Shinya Okano <tokibito@gmail.com>
@@ -36,6 +36,11 @@ Dynamic: license-file
36
36
 
37
37
  # django-database-task
38
38
 
39
+ [![CI](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml/badge.svg)](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
40
+ [![PyPI version](https://badge.fury.io/py/django-database-task.svg)](https://badge.fury.io/py/django-database-task)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-database-task.svg)](https://pypi.org/project/django-database-task/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
43
+
39
44
  A database-backed task queue backend for Django 6.0's built-in task framework.
40
45
 
41
46
  ## Features
@@ -607,21 +612,68 @@ pip install django-database-task[cloudtasks]
607
612
  TASKS = {
608
613
  "default": {
609
614
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
610
- "OPTIONS": {
611
- "CLOUD_TASKS_QUEUE": "default", # Only required setting
612
- },
615
+ "QUEUES": [], # Allow all queue names
613
616
  },
614
617
  }
615
618
  ```
616
619
 
617
- Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment variables.
620
+ Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
618
621
 
619
- ### How It Works
622
+ **Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
623
+ ```python
624
+ "QUEUES": ["default", "emails", "batch"], # Only these queues allowed
625
+ ```
626
+
627
+ The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
628
+
629
+ ```python
630
+ @task # Uses "default" queue
631
+ def normal_task():
632
+ pass
633
+
634
+ @task(queue="batch") # Uses "batch" queue
635
+ def batch_task():
636
+ pass
620
637
 
638
+ @task(queue="high-priority") # Uses "high-priority" queue
639
+ def urgent_task():
640
+ pass
621
641
  ```
622
- 1. App enqueues task → Task saved to database + Cloud Task created
623
- 2. Cloud Task triggers HTTP request /tasks/execute/<task_id>/
624
- 3. Handler retrieves task from database and executes it
642
+
643
+ This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
644
+
645
+ ### How It Works
646
+
647
+ ```mermaid
648
+ sequenceDiagram
649
+ participant App as Application
650
+ participant Backend as CloudTasksDatabaseBackend
651
+ participant DB as Database
652
+ participant CT as Cloud Tasks
653
+ participant Handler as /tasks/execute/
654
+
655
+ Note over App,Handler: Task Enqueue
656
+ App->>Backend: task.enqueue(args, kwargs)
657
+ Backend->>DB: INSERT task (status=READY)
658
+ DB-->>Backend: Task ID
659
+ Backend->>CT: Create Cloud Task (task_id only)
660
+ CT-->>Backend: OK
661
+ Backend-->>App: TaskResult (id, status=READY)
662
+
663
+ Note over App,Handler: Task Execution (triggered by Cloud Tasks)
664
+ CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
665
+ Handler->>Handler: Verify OIDC token (optional)
666
+ Handler->>DB: SELECT task by ID
667
+ DB-->>Handler: Task record
668
+ Handler->>DB: UPDATE status=RUNNING
669
+ Handler->>Handler: Execute task function
670
+ alt Success
671
+ Handler->>DB: UPDATE status=SUCCESSFUL
672
+ Handler-->>CT: HTTP 200
673
+ else Failure
674
+ Handler->>DB: UPDATE status=FAILED
675
+ Handler-->>CT: HTTP 500 (triggers retry)
676
+ end
625
677
  ```
626
678
 
627
679
  The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
@@ -636,10 +688,9 @@ TASKS = {
636
688
  "default": {
637
689
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
638
690
  "OPTIONS": {
639
- # Required
640
- "CLOUD_TASKS_QUEUE": "default",
691
+ # All settings are optional - auto-detected from environment
641
692
 
642
- # Auto-detected (override if needed)
693
+ # Override auto-detection if needed
643
694
  # "CLOUD_TASKS_PROJECT": "my-project",
644
695
  # "CLOUD_TASKS_LOCATION": "asia-northeast1",
645
696
  # "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
@@ -655,11 +706,12 @@ TASKS = {
655
706
 
656
707
  ### Auto-Detection
657
708
 
658
- | Setting | Environment Variable | Description |
659
- |---------|---------------------|-------------|
660
- | Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
661
- | Location | `CLOUD_RUN_REGION` / `GAE_REGION` | Cloud Tasks region |
709
+ | Setting | Detection Method | Description |
710
+ |---------|------------------|-------------|
711
+ | Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
712
+ | Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
662
713
  | Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
714
+ | Queue name | Task's `queue_name` attribute | Defaults to "default" |
663
715
 
664
716
  ### OIDC Authentication
665
717
 
@@ -670,8 +722,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
670
722
  TASKS = {
671
723
  "default": {
672
724
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
725
+ "QUEUES": [], # Allow all queue names
673
726
  "OPTIONS": {
674
- "CLOUD_TASKS_QUEUE": "default",
675
727
  "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
676
728
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
677
729
  },
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "django-database-task"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "A database-backed task queue backend for Django 6.0's built-in task framework"
9
9
  readme = "README.md"
10
10
  license = "MIT"