Skip to content

Redis, tasks, and scheduled jobs

Redis sidecar

add_django_website(..., redis_sidecar=True) (default) attaches a Redis container (mcr.microsoft.com/mirror/docker/library/redis:7.2) to the Web App and sets REDIS_SIDECAR=true.

Django settings then configure django_redis against redis://localhost:6379/0, with exceptions ignored so the site can start if Redis is briefly unavailable.

Django tasks

django_tasks=True (default) requires redis_sidecar=True and sets DJANGO_TASKS=true. Settings wire:

  • RQ_QUEUES using the Redis cache
  • TASKS backend django_tasks_rq.RQBackend

patch_django_settings_for_azure adds django_rq and django_tasks_rq to INSTALLED_APPS.

When DJANGO_TASKS=true, startup starts the worker through supervisorctl:

python manage.py rqworker --job-class django_tasks_rq.Job

(with a long timeout so Entra credentials can refresh). The program is defined with autostart=false, so an app that disables tasks never runs it, and its output goes to the container's stdout/stderr so it appears in the App Service log stream.

Worker only accepts django.tasks Tasks

The worker uses django_tasks_rq.Job, which rejects plain callables with SuspiciousOperation: Task … does not point to a Task. Background work must be defined with @task / @task() and enqueued via .enqueue().

Scheduled tasks (rqcron)

django_rq_cron=True (default False) requires redis_sidecar=True and sets:

  • DJANGO_RQ_CRON=true
  • RQ_CRON_CONFIG defaulting to cron_config.py

Override the config path by passing RQ_CRON_CONFIG in environment_variables before the default is applied.

At startup, supervisord runs the RQ worker. When DJANGO_RQ_CRON=true, startup also starts the cron program (defined in cicd/supervisord.conf with autostart=false):

python manage.py rqcron $RQ_CRON_CONFIG

(with the same 6-hour timeout pattern as the RQ worker).

Registering cron jobs (required pattern)

Because the worker only accepts django-tasks Tasks, do not call rq.cron.register with a plain function, and do not pass a Task object directly to rq.cron.register (Task has no __name__, so config import fails).

Use pulumi_django_azure.cron.register_task with a @task-decorated callable:

# cron_config.py
from django.tasks import task
from pulumi_django_azure.cron import register_task


@task()
def send_report() -> None:
    ...


register_task(send_report, queue_name="default", cron="0 9 * * *")

Or register a Task defined elsewhere:

# cron_config.py
from myapp.tasks import send_report
from pulumi_django_azure.cron import register_task

register_task(send_report, queue_name="default", cron="0 9 * * *")

Use queue_name="default" so the existing supervisord RQ worker picks up scheduled jobs.

Why a helper?

register_task adapts the Task for RQ cron registration and enqueues via task.enqueue() so jobs carry the metadata django_tasks_rq.Job expects. Plain rq.cron.register(func) and rq.cron.register(task) are both broken under the default django_tasks=True worker.

Enable in Pulumi:

django.add_django_website(
    # ...
    django_rq_cron=True,
)

Custom config path:

django.add_django_website(
    # ...
    environment_variables={"RQ_CRON_CONFIG": "myapp/cron_config.py"},
    django_rq_cron=True,
)

Setting django_rq_cron=True with redis_sidecar=False raises ValueError.

Disabling

django.add_django_website(
    # ...
    redis_sidecar=False,
    django_tasks=False,
)

Setting django_tasks=True with redis_sidecar=False raises ValueError.