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.
- {django_database_task-0.2.0/django_database_task.egg-info → django_database_task-0.2.2}/PKG-INFO +69 -17
- {django_database_task-0.2.0 → django_database_task-0.2.2}/README.md +68 -16
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/__init__.py +1 -1
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/backends.py +10 -6
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/backend.py +14 -10
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/detection.py +42 -5
- {django_database_task-0.2.0 → django_database_task-0.2.2/django_database_task.egg-info}/PKG-INFO +69 -17
- {django_database_task-0.2.0 → django_database_task-0.2.2}/pyproject.toml +1 -1
- {django_database_task-0.2.0 → django_database_task-0.2.2}/LICENSE +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/MANIFEST.in +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/admin.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/apps.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/cloudtasks/auth.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/executor.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/locale/ja/LC_MESSAGES/django.mo +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/locale/ja/LC_MESSAGES/django.po +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/purge_completed_database_tasks.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/management/commands/run_database_tasks.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/migrations/0001_initial.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/migrations/__init__.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/models.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/urls.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task/views.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/SOURCES.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/dependency_links.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/requires.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/django_database_task.egg-info/top_level.txt +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/setup.cfg +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_admin.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_backend.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_commands.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_executor.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_models.py +0 -0
- {django_database_task-0.2.0 → django_database_task-0.2.2}/tests/test_views.py +0 -0
{django_database_task-0.2.0/django_database_task.egg-info → django_database_task-0.2.2}/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.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
|
+
[](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
|
|
40
|
+
[](https://badge.fury.io/py/django-database-task)
|
|
41
|
+
[](https://pypi.org/project/django-database-task/)
|
|
42
|
+
[](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
|
-
"
|
|
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
|
|
620
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
618
621
|
|
|
619
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
#
|
|
640
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
691
|
+
# All settings are optional - auto-detected from environment
|
|
641
692
|
|
|
642
|
-
#
|
|
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 |
|
|
659
|
-
|
|
660
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
661
|
-
| Location | `CLOUD_RUN_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
|
+
[](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
|
|
4
|
+
[](https://badge.fury.io/py/django-database-task)
|
|
5
|
+
[](https://pypi.org/project/django-database-task/)
|
|
6
|
+
[](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
|
-
"
|
|
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
|
|
584
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
582
585
|
|
|
583
|
-
|
|
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
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
-
#
|
|
604
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
655
|
+
# All settings are optional - auto-detected from environment
|
|
605
656
|
|
|
606
|
-
#
|
|
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 |
|
|
623
|
-
|
|
624
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
625
|
-
| Location | `CLOUD_RUN_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
|
},
|
|
@@ -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.2}/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.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.
|
{django_database_task-0.2.0 → django_database_task-0.2.2/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.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
|
+
[](https://github.com/tokibito/django-database-task/actions/workflows/ci.yml)
|
|
40
|
+
[](https://badge.fury.io/py/django-database-task)
|
|
41
|
+
[](https://pypi.org/project/django-database-task/)
|
|
42
|
+
[](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
|
-
"
|
|
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
|
|
620
|
+
Project ID, location, and handler URL are auto-detected from GAE/Cloud Run environment.
|
|
618
621
|
|
|
619
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
-
#
|
|
640
|
-
"CLOUD_TASKS_QUEUE": "default",
|
|
691
|
+
# All settings are optional - auto-detected from environment
|
|
641
692
|
|
|
642
|
-
#
|
|
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 |
|
|
659
|
-
|
|
660
|
-
| Project | `GOOGLE_CLOUD_PROJECT` | GCP project ID |
|
|
661
|
-
| Location | `CLOUD_RUN_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
|
},
|
|
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.2}/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.2}/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.2}/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
|