A Google Cloud Tasks backend for Django 6.0's built-in task framework
Project description
django-tasks-cloud-tasks
A Google Cloud Tasks backend for Django 6.0's built-in task framework.
Features
- Cloud Tasks integration - Enqueue tasks to Google Cloud Tasks
- HTTP callback execution - Tasks are executed via HTTP POST requests from Cloud Tasks
- OIDC authentication - Secure task execution with OIDC token verification
- Auto-detection - Automatically detects GCP project, location, and service URL on Cloud Run/App Engine
- Priority support - Tasks can have priorities
- Delayed execution - Schedule tasks to run at a specific time with
run_after - Task context - Access task metadata via context
Architecture
sequenceDiagram
participant App as Application
participant Backend as CloudTasksBackend
participant CT as Cloud Tasks
participant Handler as /cloudtasks/execute/
Note over App,Handler: Task Enqueue
App->>Backend: task.enqueue(args, kwargs)
Backend->>Backend: Serialize task data
Backend->>CT: Create HTTP Task (with payload)
CT-->>Backend: Task name
Backend-->>App: TaskResult (id, status=NEW)
Note over App,Handler: Task Execution (triggered by Cloud Tasks)
CT->>Handler: POST /cloudtasks/execute/<br/>(with OIDC token if configured)
Handler->>Handler: Verify OIDC token (optional)
Handler->>Handler: Deserialize task data
Handler->>Handler: Execute task function
alt Success
Handler-->>CT: HTTP 200
else Failure
Handler-->>CT: HTTP 500 (triggers retry)
end
Requirements
- Python 3.12+
- Django 6.0+
- google-cloud-tasks
- google-auth (for OIDC verification)
Installation
pip install django-tasks-cloud-tasks
Or install with dependencies:
pip install django-tasks-cloud-tasks google-cloud-tasks google-auth
Quick Start
1. Add to INSTALLED_APPS
INSTALLED_APPS = [
# ...
'django_tasks_cloud_tasks',
]
2. Configure the task backend
On Cloud Run / App Engine, all settings are auto-detected from the environment. You only need:
TASKS = {
'default': {
'BACKEND': 'django_tasks_cloud_tasks.CloudTasksBackend',
'QUEUES': [], # Empty list allows all queue names
},
}
Note: On GCP environments (Cloud Run, App Engine, GCE), the following are automatically detected:
- Project ID: from
GOOGLE_CLOUD_PROJECTenv var or GCP metadata server- Location: from
CLOUD_TASKS_LOCATION,CLOUD_RUN_REGIONenv var, or metadata server- Service URL: from
SERVICE_URLenv var, or generated fromK_SERVICE(Cloud Run) /GAE_SERVICE(App Engine)- Service Account: from metadata server (for OIDC authentication)
About Service Accounts: On GCP, applications run with a runtime service account (not API keys or JSON key files). Cloud Run, App Engine, and GCE automatically provide credentials via the metadata server. You don't need to create or download any key files.
Simply grant the
roles/cloudtasks.enqueuerrole to your runtime service account:# For Cloud Run (uses Compute Engine default service account by default) gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \ --role="roles/cloudtasks.enqueuer"The backend will automatically use these credentials for both creating tasks and OIDC authentication.
For local development, set environment variables:
export GOOGLE_CLOUD_PROJECT="your-project-id"
export CLOUD_TASKS_LOCATION="asia-northeast1"
export SERVICE_URL="http://localhost:8000"
With these environment variables set, the same minimal configuration works:
TASKS = {
'default': {
'BACKEND': 'django_tasks_cloud_tasks.CloudTasksBackend',
'QUEUES': [],
},
}
Or configure explicitly in settings:
TASKS = {
'default': {
'BACKEND': 'django_tasks_cloud_tasks.CloudTasksBackend',
'QUEUES': [],
'OPTIONS': {
'CLOUD_TASKS_PROJECT': 'your-project-id',
'CLOUD_TASKS_LOCATION': 'asia-northeast1',
'TASK_HANDLER_HOST': 'http://localhost:8000',
},
},
}
3. Add URL configuration
# urls.py
from django.urls import path, include
urlpatterns = [
path('cloudtasks/', include('django_tasks_cloud_tasks.urls')),
]
4. Define a task
from django.tasks import task
@task
def send_welcome_email(user_id):
user = User.objects.get(id=user_id)
# Send email...
return f"Email sent to {user.email}"
5. Enqueue the task
result = send_welcome_email.enqueue(user_id=123)
print(f"Task ID: {result.id}")
6. Create Cloud Tasks queue
gcloud tasks queues create default --location=asia-northeast1
Usage
Important: JSON-Serializable Parameters
Task arguments, keyword arguments, and return values must be JSON-serializable.
Supported types:
str,int,float,bool,Nonedict(with JSON-serializable keys and values)list,tuple(with JSON-serializable elements)
Not supported (will raise TypeError):
datetime,date,time- convert to ISO string:dt.isoformat()UUID- convert to string:str(uuid)Decimal- convert to float or string- Custom objects - serialize manually
from django.tasks import task
# ❌ This will raise TypeError
@task
def bad_task(user_id, created_at):
pass
bad_task.enqueue(123, datetime.now()) # TypeError!
# ✅ Convert to JSON-serializable types
@task
def good_task(user_id, created_at_iso):
created_at = datetime.fromisoformat(created_at_iso)
# ...
good_task.enqueue(123, datetime.now().isoformat()) # OK
Task with priority
@task(priority=10) # Higher priority
def urgent_task():
pass
@task(priority=-10) # Lower priority
def background_task():
pass
Delayed execution
from datetime import timedelta
from django.utils import timezone
# Run 1 hour from now
delayed_task = my_task.using(run_after=timezone.now() + timedelta(hours=1))
result = delayed_task.enqueue()
Task with context
@task(takes_context=True)
def task_with_context(context, message):
task_id = context.task_result.id
attempt = context.attempt
return f"Task {task_id} (attempt {attempt}): {message}"
Queue-specific tasks
@task(queue_name="high-priority")
def urgent_notification():
pass
# Create the queue in Cloud Tasks
# gcloud tasks queues create high-priority --location=asia-northeast1
Configuration Options
TASKS = {
'default': {
'BACKEND': 'django_tasks_cloud_tasks.CloudTasksBackend',
'QUEUES': [], # Empty list allows all queue names
'OPTIONS': {
# Auto-detected on Cloud Run / App Engine, or set explicitly
'CLOUD_TASKS_PROJECT': 'your-project-id',
'CLOUD_TASKS_LOCATION': 'asia-northeast1',
'TASK_HANDLER_HOST': 'https://your-app.run.app',
'TASK_HANDLER_PATH': '/cloudtasks/execute/', # default
# Optional: OIDC authentication
'OIDC_SERVICE_ACCOUNT_EMAIL': 'cloud-tasks-invoker@your-project.iam.gserviceaccount.com',
'OIDC_AUDIENCE': 'https://your-app.run.app',
},
},
}
Configuration Reference
| Option | Required | Description |
|---|---|---|
CLOUD_TASKS_PROJECT |
Auto-detected | GCP project ID |
CLOUD_TASKS_LOCATION |
Auto-detected | Cloud Tasks location (e.g., asia-northeast1) |
TASK_HANDLER_HOST |
Auto-detected | Base URL for task execution endpoint |
TASK_HANDLER_PATH |
No | Task execution endpoint path (default: /cloudtasks/execute/) |
OIDC_SERVICE_ACCOUNT_EMAIL |
No | Service account email for OIDC token |
OIDC_AUDIENCE |
No | OIDC audience (defaults to TASK_HANDLER_HOST) |
Auto-Detection
Settings are automatically detected from environment variables or GCP metadata:
| Setting | Detection Source |
|---|---|
CLOUD_TASKS_PROJECT |
GOOGLE_CLOUD_PROJECT env var, or metadata server |
CLOUD_TASKS_LOCATION |
CLOUD_TASKS_LOCATION, CLOUD_RUN_REGION env var, or metadata server |
TASK_HANDLER_HOST |
SERVICE_URL env var, or built from K_SERVICE (Cloud Run) / GAE_SERVICE (App Engine) |
Environment Variables
For local development:
| Environment Variable | Description |
|---|---|
GOOGLE_CLOUD_PROJECT |
GCP project ID |
CLOUD_TASKS_LOCATION |
Cloud Tasks location |
SERVICE_URL |
Task execution endpoint URL |
CLOUD_TASKS_EMULATOR_HOST |
Cloud Tasks emulator host (for local development) |
HTTP Endpoint
POST /cloudtasks/execute/
Task execution endpoint called by Cloud Tasks.
Request body (JSON):
{
"task_id": "uuid",
"task_path": "myapp.tasks.send_email",
"args": [1, 2, 3],
"kwargs": {"key": "value"},
"queue_name": "default",
"backend": "default",
"priority": 0,
"takes_context": false,
"enqueued_at": "2024-01-01T00:00:00+00:00"
}
Response (success):
{"status": "success", "task_id": "uuid"}
Response (error):
{"status": "error", "task_id": "uuid", "error": "Error message"}
OIDC Authentication
When deploying to production, enable OIDC authentication to secure the task execution endpoint.
Setup
-
Create a service account for OIDC:
gcloud iam service-accounts create cloud-tasks-invoker \ --display-name="Cloud Tasks Invoker"
-
Grant required roles:
# Allow your service to create Cloud Tasks gcloud projects add-iam-policy-binding PROJECT_ID \ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \ --role="roles/cloudtasks.enqueuer" # Allow impersonation for OIDC gcloud iam service-accounts add-iam-policy-binding \ cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com \ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \ --role="roles/iam.serviceAccountUser"
-
Configure the backend:
TASKS = { 'default': { 'BACKEND': 'django_tasks_cloud_tasks.CloudTasksBackend', 'QUEUES': [], # Empty list allows all queue names 'OPTIONS': { # CLOUD_TASKS_PROJECT, CLOUD_TASKS_LOCATION, TASK_HANDLER_HOST are auto-detected on Cloud Run 'OIDC_SERVICE_ACCOUNT_EMAIL': 'cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com', }, }, }
Local Development
Without Cloud Tasks Emulator
You can manually simulate task execution:
# Start Django server
export GOOGLE_CLOUD_PROJECT="your-project-id"
export CLOUD_TASKS_LOCATION="asia-northeast1"
export SERVICE_URL="http://localhost:8000"
python manage.py runserver
# Simulate task execution
curl -X POST http://localhost:8000/cloudtasks/execute/ \
-H "Content-Type: application/json" \
-d '{
"task_id": "test-task-001",
"task_path": "myapp.tasks.add_numbers",
"args": [5, 3],
"kwargs": {},
"queue_name": "default",
"backend": "default",
"priority": 0,
"takes_context": false,
"enqueued_at": "2024-01-01T00:00:00+00:00"
}'
With Cloud Tasks Emulator
# Start Cloud Tasks emulator
gcloud beta emulators tasks start --host-port=localhost:8123
# Set environment variables
export CLOUD_TASKS_EMULATOR_HOST=localhost:8123
export GOOGLE_CLOUD_PROJECT="sample-project"
export CLOUD_TASKS_LOCATION="asia-northeast1"
export SERVICE_URL="http://localhost:8000"
# Create queues
gcloud tasks queues create default --location=asia-northeast1 --project=sample-project
# Start Django server
python manage.py runserver
Deployment to Cloud Run
1. Create Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", ":8080", "myproject.wsgi:application"]
2. Deploy
# Deploy to Cloud Run
gcloud run deploy myapp \
--source . \
--region asia-northeast1 \
--allow-unauthenticated
# Create Cloud Tasks queues
gcloud tasks queues create default --location asia-northeast1
gcloud tasks queues create high-priority --location asia-northeast1
3. Configuration
All settings are auto-detected on Cloud Run. No additional configuration needed for basic usage.
Example Project
See the examples/ directory for a complete sample project with a web UI for testing task enqueueing.
License
MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_tasks_cloud_tasks-0.1.0.tar.gz.
File metadata
- Download URL: django_tasks_cloud_tasks-0.1.0.tar.gz
- Upload date:
- Size: 19.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b5ea10956bb43c184bc6e10504c47e723ed86ce7f43846d8c4f0a353bd0fe4
|
|
| MD5 |
5194af2f96e0869951b74bd2de0b9ba9
|
|
| BLAKE2b-256 |
ce8fe3ae2b88f828bafdb1fb8175fb2c59d9fcd9b14b6b5fb067c6c50c59b6c8
|
File details
Details for the file django_tasks_cloud_tasks-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_tasks_cloud_tasks-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc5ce8f9f9e1ae6b1eaaab9d12c8e064bde393a02d2bf686bc4db750aefcacd7
|
|
| MD5 |
e9abb1c1e4ac59d2c08fcf0d56e56476
|
|
| BLAKE2b-256 |
9f878ab26aa3b9b0d1517764bb06e50acfc85d15cf1fc0d3ccd08fb811e78402
|