> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the docs for Sevalla, a platform for deploying applications, databases, static sites, object storage and load balancers. The dashboard is at https://app.sevalla.com.
> Bold text in steps is an exact dashboard label.
> To act on a Sevalla account, prefer the Sevalla MCP server (https://mcp.sevalla.com/mcp, see https://docs.sevalla.com/ai-agents/overview.md), then the Sevalla CLI (https://docs.sevalla.com/developer-tools/cli.md), then the REST API (https://api-docs.sevalla.com, OpenAPI spec at https://api.sevalla.com/v3/openapi.json).
> Every page index is at https://docs.sevalla.com/llms.txt.

# Run Django background tasks

> Run Django background tasks with Celery on Sevalla: a Redis database as the broker, a background worker process for the queue, and cron jobs or Celery beat for schedules.

A background task is work that runs outside the request, such as sending email or resizing images. On Sevalla, Celery runs the tasks in a background worker process, built from the same image as the web process, and a Redis database holds the queue between them.

Django 6.0 added a tasks framework (`django.tasks`) for defining and enqueuing tasks, but Django doesn't run them: its built-in backends are for development and testing only. Celery provides both the queue and the worker.

## Before you begin

* A Django project deployed on Sevalla, as in [Deploy Django](/guides/python/django/deploy).

## Create a Redis database

<Steps>
  <Step title="Create the database">
    In the sidebar, click **Databases**, then click **Create database**. Under **Database**, choose **Redis**, or **Valkey**: the code in this guide works with both. Enter `storefront-redis` as the **Display name**, choose the same **Data center** as the application and a **Size**, then click **Create database**.
  </Step>

  <Step title="Connect it to the application">
    In the sidebar, click **Applications**, then click the application. Click the **Networking** tab. Under **Connected services**, click **Add internal connection**. Choose `storefront-redis` as the **Service**, turn on **Add environment variables to the application**, and click **Add internal connection**. Sevalla adds `REDIS_HOST`, `REDIS_PORT`, `REDIS_PASSWORD` and `REDIS_URL`. See [Connect an application](/databases/connect#connect-an-application).
  </Step>
</Steps>

## Add Celery to the project

Install Celery with its Redis support, and update `requirements.txt`:

```bash theme={null}
pip install "celery[redis]"
pip freeze > requirements.txt
```

Create the Celery application next to `settings.py`:

```python storefront/celery.py theme={null}
import os

from celery import Celery

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "storefront.settings")

app = Celery("storefront")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()
```

Load it when Django starts:

```python storefront/__init__.py theme={null}
from .celery import app as celery_app

__all__ = ("celery_app",)
```

Point Celery at Redis in `storefront/settings.py`. Settings that start with `CELERY_` configure Celery:

```python storefront/settings.py theme={null}
# A Valkey database's URL starts with valkey://, which Celery doesn't accept.
CELERY_BROKER_URL = env("REDIS_URL", default="redis://localhost:6379/0").replace("valkey://", "redis://", 1)
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True
```

Add a task in one of your Django apps, for example an `orders` app listed in `INSTALLED_APPS`. Celery finds `tasks.py` in every installed app:

```python orders/tasks.py theme={null}
from celery import shared_task


@shared_task
def send_order_confirmation(order_id):
    print(f"Sending the confirmation for order {order_id}")
```

Queue it from a view or anywhere else with `send_order_confirmation.delay(order.id)`. Commit and push the changes.

## Run the worker on Sevalla

<Steps>
  <Step title="Create the background worker">
    On the application's **Processes** tab, click **Create process**. Choose **Background worker**, enter `Celery worker` as the **Name** and this **Custom start command**:

    ```bash theme={null}
    celery -A storefront worker --loglevel INFO --concurrency 2
    ```

    Choose a **Resource** and click **Create process**.
  </Step>

  <Step title="Deploy">
    Click **Deploy** in the undeployed changes bar at the bottom of the page.
  </Step>
</Steps>

Set `--concurrency` to match the size. Without it, Celery starts one worker process per CPU of the machine it runs on, which can be more than the process's memory holds. Two processes fit in **H1** (0.3 GB of memory). To process more tasks at once, add instances in the process's **Scaling** section, or choose a larger size and raise `--concurrency`. See [Scaling](/applications/scaling).

<Frame>
  <img className="block dark:hidden" src="https://assets.sevalla.com/screenshots/light/app-processes-worker-create.png" alt="The Create process sheet with Background worker selected, the Name and Custom start command fields, the resource and the scaling settings" width="768" />

  <img className="hidden dark:block" src="https://assets.sevalla.com/screenshots/dark/app-processes-worker-create.png" alt="The Create process sheet with Background worker selected, the Name and Custom start command fields, the resource and the scaling settings" width="768" />
</Frame>

## Run tasks on a schedule

Run scheduled work as a [cron job](/applications/processes#cron-jobs): Sevalla starts a new instance at each scheduled time, runs the command, and stops it. Put the work in a management command, then create the process:

<Steps>
  <Step title="Create the cron job">
    On the application's **Processes** tab, click **Create process**. Choose **Cron job**, enter `Clear sessions` as the **Name**, `python manage.py clearsessions` as the **Custom start command**, and `0 3 * * *` as the **Schedule** (every day at 03:00 UTC). Click **Create process**.
  </Step>

  <Step title="Deploy">
    Click **Deploy** in the undeployed changes bar at the bottom of the page.
  </Step>
</Steps>

Schedules run in UTC unless you turn on **Set custom time zone**. To keep the schedule in Celery instead, run Celery beat in a second background worker with the start command `celery -A storefront beat --loglevel INFO`, and keep that process at 1 instance: each beat instance sends every scheduled task.

## Verify

1. Click the **Web terminal** tab, choose the **Web** process, and queue a task:

   ```bash theme={null}
   . /opt/venv/bin/activate
   python manage.py shell -c "from orders.tasks import send_order_confirmation; send_order_confirmation.delay(42)"
   ```

2. Click the **Logs** tab and look at the worker's runtime logs. They show `Task orders.tasks.send_order_confirmation[...] received`, the line `Sending the confirmation for order 42`, and `Task orders.tasks.send_order_confirmation[...] succeeded`.

On the **Processes** tab, the `Celery worker` process shows **Running**. If it shows **Crashed**, the logs show why, for example `Error 111 connecting` when `REDIS_URL` is missing or wrong.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.