django-database-task 0.2.0__tar.gz → 0.2.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.
- {django_database_task-0.2.0/django_database_task.egg-info → django_database_task-0.2.1}/PKG-INFO +64 -17
- {django_database_task-0.2.0 → django_database_task-0.2.1}/README.md +63 -16
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/__init__.py +1 -1
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/backends.py +10 -6
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/backend.py +14 -10
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/detection.py +42 -5
- {django_database_task-0.2.0 → django_database_task-0.2.1/django_database_task.egg-info}/PKG-INFO +64 -17
- {django_database_task-0.2.0 → django_database_task-0.2.1}/pyproject.toml +1 -1
- {django_database_task-0.2.0 → django_database_task-0.2.1}/LICENSE +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/MANIFEST.in +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/admin.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/apps.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/auth.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/executor.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/locale/ja/LC_MESSAGES/django.mo +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/locale/ja/LC_MESSAGES/django.po +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/management/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/management/commands/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/management/commands/purge_completed_database_tasks.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/management/commands/run_database_tasks.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/migrations/0001_initial.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/migrations/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/models.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/urls.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/views.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/SOURCES.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/dependency_links.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/requires.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/top_level.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/setup.cfg +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_admin.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_backend.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_commands.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_executor.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_models.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.1}/tests/test_views.py +0 -0
{django_database_task-0.2.0/django_database_task.egg-info → django_database_task-0.2.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-database-task
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
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>
|
|
@@ -607,21 +607,68 @@ pip install django-database-task[cloudtasks]
|
|
|
607
607
|
TASKS = {
|
|
608
608
|
"default": {
|
|
609
609
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
610
|
-
"
|
|
611
|
-
"CLOUD_TASKS_QUEUE": "default", # Only required setting
|
|
612
|
-
},
|
|
610
|
+
"QUEUES": [], # Allow all queue names
|
|
613
611
|
},
|
|
614
612
|
}
|
|
615
613
|
```
|
|
616
614
|
|
|
617
|
-
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment
|
|
615
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
618
616
|
|
|
619
|
-
|
|
617
|
+
**Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
|
|
618
|
+
```python
|
|
619
|
+
"QUEUES": ["default", "emails", "batch"], # Only these queues allowed
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
|
|
620
623
|
|
|
624
|
+
```python
|
|
625
|
+
@task # Uses "default" queue
|
|
626
|
+
def normal_task():
|
|
627
|
+
pass
|
|
628
|
+
|
|
629
|
+
@task(queue="batch") # Uses "batch" queue
|
|
630
|
+
def batch_task():
|
|
631
|
+
pass
|
|
632
|
+
|
|
633
|
+
@task(queue="high-priority") # Uses "high-priority" queue
|
|
634
|
+
def urgent_task():
|
|
635
|
+
pass
|
|
621
636
|
```
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
637
|
+
|
|
638
|
+
This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
|
|
639
|
+
|
|
640
|
+
### How It Works
|
|
641
|
+
|
|
642
|
+
```mermaid
|
|
643
|
+
sequenceDiagram
|
|
644
|
+
participant App as Application
|
|
645
|
+
participant Backend as CloudTasksDatabaseBackend
|
|
646
|
+
participant DB as Database
|
|
647
|
+
participant CT as Cloud Tasks
|
|
648
|
+
participant Handler as /tasks/execute/
|
|
649
|
+
|
|
650
|
+
Note over App,Handler: Task Enqueue
|
|
651
|
+
App->>Backend: task.enqueue(args, kwargs)
|
|
652
|
+
Backend->>DB: INSERT task (status=READY)
|
|
653
|
+
DB-->>Backend: Task ID
|
|
654
|
+
Backend->>CT: Create Cloud Task (task_id only)
|
|
655
|
+
CT-->>Backend: OK
|
|
656
|
+
Backend-->>App: TaskResult (id, status=READY)
|
|
657
|
+
|
|
658
|
+
Note over App,Handler: Task Execution (triggered by Cloud Tasks)
|
|
659
|
+
CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
|
|
660
|
+
Handler->>Handler: Verify OIDC token (optional)
|
|
661
|
+
Handler->>DB: SELECT task by ID
|
|
662
|
+
DB-->>Handler: Task record
|
|
663
|
+
Handler->>DB: UPDATE status=RUNNING
|
|
664
|
+
Handler->>Handler: Execute task function
|
|
665
|
+
alt Success
|
|
666
|
+
Handler->>DB: UPDATE status=SUCCESSFUL
|
|
667
|
+
Handler-->>CT: HTTP 200
|
|
668
|
+
else Failure
|
|
669
|
+
Handler->>DB: UPDATE status=FAILED
|
|
670
|
+
Handler-->>CT: HTTP 500 (triggers retry)
|
|
671
|
+
end
|
|
625
672
|
```
|
|
626
673
|
|
|
627
674
|
The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
|
|
@@ -636,10 +683,9 @@ TASKS = {
|
|
|
636
683
|
"default": {
|
|
637
684
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
638
685
|
"OPTIONS": {
|
|
639
|
-
#
|
|
640
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
686
|
+
# All settings are optional - auto-detected from environment
|
|
641
687
|
|
|
642
|
-
#
|
|
688
|
+
# Override auto-detection if needed
|
|
643
689
|
# "CLOUD_TASKS_PROJECT": "my-project",
|
|
644
690
|
# "CLOUD_TASKS_LOCATION": "asia-northeast1",
|
|
645
691
|
# "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
|
|
@@ -655,11 +701,12 @@ TASKS = {
|
|
|
655
701
|
|
|
656
702
|
### Auto-Detection
|
|
657
703
|
|
|
658
|
-
| Setting |
|
|
659
|
-
|
|
660
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
661
|
-
| Location | `CLOUD_RUN_REGION`
|
|
704
|
+
| Setting | Detection Method | Description |
|
|
705
|
+
|---------|------------------|-------------|
|
|
706
|
+
| Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
|
|
707
|
+
| Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
|
|
662
708
|
| Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
|
|
709
|
+
| Queue name | Task's `queue_name` attribute | Defaults to "default" |
|
|
663
710
|
|
|
664
711
|
### OIDC Authentication
|
|
665
712
|
|
|
@@ -670,8 +717,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
|
|
|
670
717
|
TASKS = {
|
|
671
718
|
"default": {
|
|
672
719
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
720
|
+
"QUEUES": [], # Allow all queue names
|
|
673
721
|
"OPTIONS": {
|
|
674
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
675
722
|
"OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
|
|
676
723
|
# OIDC_AUDIENCE is auto-detected from handler URL if not set
|
|
677
724
|
},
|
|
@@ -571,21 +571,68 @@ pip install django-database-task[cloudtasks]
|
|
|
571
571
|
TASKS = {
|
|
572
572
|
"default": {
|
|
573
573
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
574
|
-
"
|
|
575
|
-
"CLOUD_TASKS_QUEUE": "default", # Only required setting
|
|
576
|
-
},
|
|
574
|
+
"QUEUES": [], # Allow all queue names
|
|
577
575
|
},
|
|
578
576
|
}
|
|
579
577
|
```
|
|
580
578
|
|
|
581
|
-
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment
|
|
579
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
582
580
|
|
|
583
|
-
|
|
581
|
+
**Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
|
|
582
|
+
```python
|
|
583
|
+
"QUEUES": ["default", "emails", "batch"], # Only these queues allowed
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
|
|
584
587
|
|
|
588
|
+
```python
|
|
589
|
+
@task # Uses "default" queue
|
|
590
|
+
def normal_task():
|
|
591
|
+
pass
|
|
592
|
+
|
|
593
|
+
@task(queue="batch") # Uses "batch" queue
|
|
594
|
+
def batch_task():
|
|
595
|
+
pass
|
|
596
|
+
|
|
597
|
+
@task(queue="high-priority") # Uses "high-priority" queue
|
|
598
|
+
def urgent_task():
|
|
599
|
+
pass
|
|
585
600
|
```
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
601
|
+
|
|
602
|
+
This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
|
|
603
|
+
|
|
604
|
+
### How It Works
|
|
605
|
+
|
|
606
|
+
```mermaid
|
|
607
|
+
sequenceDiagram
|
|
608
|
+
participant App as Application
|
|
609
|
+
participant Backend as CloudTasksDatabaseBackend
|
|
610
|
+
participant DB as Database
|
|
611
|
+
participant CT as Cloud Tasks
|
|
612
|
+
participant Handler as /tasks/execute/
|
|
613
|
+
|
|
614
|
+
Note over App,Handler: Task Enqueue
|
|
615
|
+
App->>Backend: task.enqueue(args, kwargs)
|
|
616
|
+
Backend->>DB: INSERT task (status=READY)
|
|
617
|
+
DB-->>Backend: Task ID
|
|
618
|
+
Backend->>CT: Create Cloud Task (task_id only)
|
|
619
|
+
CT-->>Backend: OK
|
|
620
|
+
Backend-->>App: TaskResult (id, status=READY)
|
|
621
|
+
|
|
622
|
+
Note over App,Handler: Task Execution (triggered by Cloud Tasks)
|
|
623
|
+
CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
|
|
624
|
+
Handler->>Handler: Verify OIDC token (optional)
|
|
625
|
+
Handler->>DB: SELECT task by ID
|
|
626
|
+
DB-->>Handler: Task record
|
|
627
|
+
Handler->>DB: UPDATE status=RUNNING
|
|
628
|
+
Handler->>Handler: Execute task function
|
|
629
|
+
alt Success
|
|
630
|
+
Handler->>DB: UPDATE status=SUCCESSFUL
|
|
631
|
+
Handler-->>CT: HTTP 200
|
|
632
|
+
else Failure
|
|
633
|
+
Handler->>DB: UPDATE status=FAILED
|
|
634
|
+
Handler-->>CT: HTTP 500 (triggers retry)
|
|
635
|
+
end
|
|
589
636
|
```
|
|
590
637
|
|
|
591
638
|
The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
|
|
@@ -600,10 +647,9 @@ TASKS = {
|
|
|
600
647
|
"default": {
|
|
601
648
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
602
649
|
"OPTIONS": {
|
|
603
|
-
#
|
|
604
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
650
|
+
# All settings are optional - auto-detected from environment
|
|
605
651
|
|
|
606
|
-
#
|
|
652
|
+
# Override auto-detection if needed
|
|
607
653
|
# "CLOUD_TASKS_PROJECT": "my-project",
|
|
608
654
|
# "CLOUD_TASKS_LOCATION": "asia-northeast1",
|
|
609
655
|
# "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
|
|
@@ -619,11 +665,12 @@ TASKS = {
|
|
|
619
665
|
|
|
620
666
|
### Auto-Detection
|
|
621
667
|
|
|
622
|
-
| Setting |
|
|
623
|
-
|
|
624
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
625
|
-
| Location | `CLOUD_RUN_REGION`
|
|
668
|
+
| Setting | Detection Method | Description |
|
|
669
|
+
|---------|------------------|-------------|
|
|
670
|
+
| Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
|
|
671
|
+
| Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
|
|
626
672
|
| Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
|
|
673
|
+
| Queue name | Task's `queue_name` attribute | Defaults to "default" |
|
|
627
674
|
|
|
628
675
|
### OIDC Authentication
|
|
629
676
|
|
|
@@ -634,8 +681,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
|
|
|
634
681
|
TASKS = {
|
|
635
682
|
"default": {
|
|
636
683
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
684
|
+
"QUEUES": [], # Allow all queue names
|
|
637
685
|
"OPTIONS": {
|
|
638
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
639
686
|
"OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
|
|
640
687
|
# OIDC_AUDIENCE is auto-detected from handler URL if not set
|
|
641
688
|
},
|
|
@@ -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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
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
|
{django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/backend.py
RENAMED
|
@@ -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
|
-
|
|
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
|
-
#
|
|
45
|
-
region = os.environ.get("
|
|
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.request
|
|
70
|
+
import urllib.error
|
|
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.
|
{django_database_task-0.2.0 → django_database_task-0.2.1/django_database_task.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-database-task
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
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>
|
|
@@ -607,21 +607,68 @@ pip install django-database-task[cloudtasks]
|
|
|
607
607
|
TASKS = {
|
|
608
608
|
"default": {
|
|
609
609
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
610
|
-
"
|
|
611
|
-
"CLOUD_TASKS_QUEUE": "default", # Only required setting
|
|
612
|
-
},
|
|
610
|
+
"QUEUES": [], # Allow all queue names
|
|
613
611
|
},
|
|
614
612
|
}
|
|
615
613
|
```
|
|
616
614
|
|
|
617
|
-
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment
|
|
615
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
618
616
|
|
|
619
|
-
|
|
617
|
+
**Important**: Set `QUEUES: []` to allow any queue name, or list the queues you use:
|
|
618
|
+
```python
|
|
619
|
+
"QUEUES": ["default", "emails", "batch"], # Only these queues allowed
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
The Cloud Tasks queue name is determined by the task's `queue_name` attribute:
|
|
620
623
|
|
|
624
|
+
```python
|
|
625
|
+
@task # Uses "default" queue
|
|
626
|
+
def normal_task():
|
|
627
|
+
pass
|
|
628
|
+
|
|
629
|
+
@task(queue="batch") # Uses "batch" queue
|
|
630
|
+
def batch_task():
|
|
631
|
+
pass
|
|
632
|
+
|
|
633
|
+
@task(queue="high-priority") # Uses "high-priority" queue
|
|
634
|
+
def urgent_task():
|
|
635
|
+
pass
|
|
621
636
|
```
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
637
|
+
|
|
638
|
+
This allows you to configure different rate limits and concurrency settings per queue in Cloud Tasks.
|
|
639
|
+
|
|
640
|
+
### How It Works
|
|
641
|
+
|
|
642
|
+
```mermaid
|
|
643
|
+
sequenceDiagram
|
|
644
|
+
participant App as Application
|
|
645
|
+
participant Backend as CloudTasksDatabaseBackend
|
|
646
|
+
participant DB as Database
|
|
647
|
+
participant CT as Cloud Tasks
|
|
648
|
+
participant Handler as /tasks/execute/
|
|
649
|
+
|
|
650
|
+
Note over App,Handler: Task Enqueue
|
|
651
|
+
App->>Backend: task.enqueue(args, kwargs)
|
|
652
|
+
Backend->>DB: INSERT task (status=READY)
|
|
653
|
+
DB-->>Backend: Task ID
|
|
654
|
+
Backend->>CT: Create Cloud Task (task_id only)
|
|
655
|
+
CT-->>Backend: OK
|
|
656
|
+
Backend-->>App: TaskResult (id, status=READY)
|
|
657
|
+
|
|
658
|
+
Note over App,Handler: Task Execution (triggered by Cloud Tasks)
|
|
659
|
+
CT->>Handler: POST /tasks/execute/<task_id>/<br/>(with OIDC token if configured)
|
|
660
|
+
Handler->>Handler: Verify OIDC token (optional)
|
|
661
|
+
Handler->>DB: SELECT task by ID
|
|
662
|
+
DB-->>Handler: Task record
|
|
663
|
+
Handler->>DB: UPDATE status=RUNNING
|
|
664
|
+
Handler->>Handler: Execute task function
|
|
665
|
+
alt Success
|
|
666
|
+
Handler->>DB: UPDATE status=SUCCESSFUL
|
|
667
|
+
Handler-->>CT: HTTP 200
|
|
668
|
+
else Failure
|
|
669
|
+
Handler->>DB: UPDATE status=FAILED
|
|
670
|
+
Handler-->>CT: HTTP 500 (triggers retry)
|
|
671
|
+
end
|
|
625
672
|
```
|
|
626
673
|
|
|
627
674
|
The Cloud Task only contains the task ID. All task parameters are stored in the database, ensuring:
|
|
@@ -636,10 +683,9 @@ TASKS = {
|
|
|
636
683
|
"default": {
|
|
637
684
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
638
685
|
"OPTIONS": {
|
|
639
|
-
#
|
|
640
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
686
|
+
# All settings are optional - auto-detected from environment
|
|
641
687
|
|
|
642
|
-
#
|
|
688
|
+
# Override auto-detection if needed
|
|
643
689
|
# "CLOUD_TASKS_PROJECT": "my-project",
|
|
644
690
|
# "CLOUD_TASKS_LOCATION": "asia-northeast1",
|
|
645
691
|
# "TASK_HANDLER_URL": "https://myapp.example.com/tasks/execute/{task_id}/",
|
|
@@ -655,11 +701,12 @@ TASKS = {
|
|
|
655
701
|
|
|
656
702
|
### Auto-Detection
|
|
657
703
|
|
|
658
|
-
| Setting |
|
|
659
|
-
|
|
660
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
661
|
-
| Location | `CLOUD_RUN_REGION`
|
|
704
|
+
| Setting | Detection Method | Description |
|
|
705
|
+
|---------|------------------|-------------|
|
|
706
|
+
| Project | `GOOGLE_CLOUD_PROJECT` env var | GCP project ID |
|
|
707
|
+
| Location | `CLOUD_RUN_REGION` env var, or metadata server | Cloud Tasks region |
|
|
662
708
|
| Handler URL | Built from `K_SERVICE`, `GAE_SERVICE`, `GAE_VERSION` | Task execution endpoint |
|
|
709
|
+
| Queue name | Task's `queue_name` attribute | Defaults to "default" |
|
|
663
710
|
|
|
664
711
|
### OIDC Authentication
|
|
665
712
|
|
|
@@ -670,8 +717,8 @@ When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC toke
|
|
|
670
717
|
TASKS = {
|
|
671
718
|
"default": {
|
|
672
719
|
"BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
|
|
720
|
+
"QUEUES": [], # Allow all queue names
|
|
673
721
|
"OPTIONS": {
|
|
674
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
675
722
|
"OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
|
|
676
723
|
# OIDC_AUDIENCE is auto-detected from handler URL if not set
|
|
677
724
|
},
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task/cloudtasks/auth.py
RENAMED
|
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
|
{django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{django_database_task-0.2.0 → django_database_task-0.2.1}/django_database_task.egg-info/requires.txt
RENAMED
|
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
|