Skip to main content

Defining Interval Schedules

Interval schedules are the most straightforward way to run periodic tasks in Celery. By using the schedule class, you can define tasks that execute at a fixed frequency, such as every 30 seconds or every hour.

In this tutorial, you will learn how to define these intervals using both raw numbers and timedelta objects, and how to configure them within your Celery application.

Prerequisites

To follow this guide, you need a Celery app instance defined in your project.

from celery import Celery

app = Celery('my_project')

Step 1: Define a Basic Interval in Seconds

The simplest way to create an interval schedule is to pass a number of seconds to the schedule class.

from celery.schedules import schedule

# Create a schedule that triggers every 10 seconds
every_ten_seconds = schedule(run_every=10.0)

print(f"Schedule frequency: {every_ten_seconds.human_seconds}")

The run_every argument accepts a float or int. When you instantiate schedule(10.0), Celery internally converts this to a timedelta object. The human_seconds property provides a readable string representation of the interval (e.g., "10.00 seconds").

Step 2: Use Timedelta for Complex Intervals

For longer intervals, using datetime.timedelta makes your code more readable.

from datetime import timedelta
from celery.schedules import schedule

# Create a schedule that triggers every 1 hour and 30 minutes
complex_interval = schedule(run_every=timedelta(hours=1, minutes=30))

Using timedelta is the recommended approach for any interval longer than a few minutes, as it clearly communicates the intent of the schedule.

Step 3: Configure the Beat Schedule

Once you have defined your intervals, you must add them to the beat_schedule setting in your Celery configuration. Celery's maybe_schedule utility allows you to use shorthand values (like raw numbers or timedelta objects) directly in the configuration dictionary.

app.conf.beat_schedule = {
'sync-data-every-30-seconds': {
'task': 'tasks.sync_data',
'schedule': 30.0, # Shorthand for schedule(30.0)
},
'cleanup-every-day': {
'task': 'tasks.cleanup',
'schedule': timedelta(days=1), # Shorthand for schedule(timedelta(days=1))
},
}

When the Celery Beat service starts, it iterates through this dictionary and converts these shorthand values into formal celery.schedules.schedule objects.

Step 4: Align Execution with Relative Schedules

By default, interval schedules are calculated based on the time the Beat service started. If you want the execution time to be rounded to the resolution of the interval, use the relative argument.

from datetime import timedelta
from celery.schedules import schedule

# This schedule will align to the minute boundary (e.g., 12:01:00, 12:02:00)
aligned_schedule = schedule(run_every=timedelta(minutes=1), relative=True)

When relative=True, the remaining_estimate calculation rounds the next run time. This is useful if you want multiple tasks with the same interval to synchronize their execution times.

Step 5: Adjust Scheduling Precision

The precision of your interval is affected by the beat_max_loop_interval setting. This setting determines the maximum time the scheduler sleeps between checking if tasks are due.

# Ensure the scheduler checks for due tasks at least every 5 seconds
app.conf.beat_max_loop_interval = 5

If you have a task scheduled to run every 10 seconds but beat_max_loop_interval is set to 300 (the default 5 minutes), your task might experience significant drift if the scheduler is sleeping. For high-frequency tasks, ensure this setting is lower than your smallest interval.

Summary of Results

You have now configured periodic tasks using interval schedules. Your tasks will:

  1. Run at the fixed frequency defined in run_every.
  2. Be automatically managed by the Celery Beat service via the beat_schedule configuration.
  3. Optionally align to interval boundaries if relative=True is used.

To start the scheduler and see your intervals in action, run the following command in your terminal:

celery -A my_project beat -l info