Skip to main content

django-tasks-cloud-tasks

CI PyPI version Python Versions Django Versions License: MIT

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_PROJECT env var or GCP metadata server
  • Location: from CLOUD_TASKS_LOCATION, CLOUD_RUN_REGION env var, or metadata server
  • Service URL: from SERVICE_URL env var, or generated from K_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.enqueuer role 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, None
  • dict (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

  1. Create a service account for OIDC:

    gcloud iam service-accounts create cloud-tasks-invoker \
        --display-name="Cloud Tasks Invoker"
    
  2. 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"
    
  3. 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

Release files for django-tasks-cloud-tasks 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-tasks-cloud-tasks 0.1.0
File Size Uploaded
django_tasks_cloud_tasks-0.1.0.tar.gz 19.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-tasks-cloud-tasks 0.1.0
File Interpreter ABI Platform
django_tasks_cloud_tasks-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.4 kB

Release files / django_tasks_cloud_tasks-0.1.0.tar.gz

Download URL django_tasks_cloud_tasks-0.1.0.tar.gz
Size 19.4 kB
Tags Source
SHA-256 checksum
How to use checksums
18b5ea10956bb43c184bc6e10504c47e723ed86ce7f43846d8c4f0a353bd0fe4
BLAKE2b-256 checksum
How to use checksums
ce8fe3ae2b88f828bafdb1fb8175fb2c59d9fcd9b14b6b5fb067c6c50c59b6c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.11

Release files / django_tasks_cloud_tasks-0.1.0-py3-none-any.whl

Download URL django_tasks_cloud_tasks-0.1.0-py3-none-any.whl
Size 15.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
fc5ce8f9f9e1ae6b1eaaab9d12c8e064bde393a02d2bf686bc4db750aefcacd7
BLAKE2b-256 checksum
How to use checksums
9f878ab26aa3b9b0d1517764bb06e50acfc85d15cf1fc0d3ccd08fb811e78402
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.11

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page