2 min read

Scheduling Tasks with Celery Beat

Celery Beat is a scheduler that kicks off tasks at regular intervals, which are then executed by available worker nodes in the cluster. It is a robust alternative to system-level cron jobs because the schedule is defined in your Python code, making it version-controllable and easier to deploy across different environments.

Why use Celery Beat over Cron?

  • Centralized Configuration: Your schedule lives with your code, not in a separate crontab file on the server.
  • Distributed Execution: The scheduler just sends a message. Any available worker on any server can pick up the task.
  • Dynamic: You can change schedules dynamically if you store them in a database (using django-celery-beat, for example).

Step 1: Define the Schedule

You define the schedule in your Celery configuration.

Assuming you have a file named tasks.py with a Celery app instance:

from celery import Celery
from celery.schedules import crontab

app = Celery('tasks', broker='redis://localhost:6379/0')

@app.task
def print_hello():
    print("Hello from Celery Beat!")

# Configure the schedule
app.conf.beat_schedule = {
    # Name of the schedule entry
    'say-hello-every-30-seconds': {
        'task': 'tasks.print_hello',
        'schedule': 30.0, # Run every 30 seconds
        'args': (),
    },
    # Using crontab syntax
    'run-every-morning': {
        'task': 'tasks.print_hello',
        'schedule': crontab(hour=7, minute=30), # Run daily at 7:30 AM
        'args': (),
    },
}

# Set timezone (Important for crontab schedules!)
app.conf.timezone = 'UTC'

Step 2: Understanding Schedules

Interval

Simple float/integer values represent seconds. 'schedule': 10.0 -> Every 10 seconds.

Crontab

The crontab class allows for complex schedules similar to Unix cron.

from celery.schedules import crontab

# Every minute
crontab(minute='*')

# Every hour at minute 0 (e.g., 1:00, 2:00)
crontab(minute=0, hour='*')

# Every Monday at 8:00 AM
crontab(hour=8, minute=0, day_of_week=1)

Step 3: Running the Services

Celery Beat requires two processes to run:

  1. The Worker: Executes the tasks.
  2. The Beat Scheduler: Triggers the tasks.

You can run them in separate terminals.

Terminal 1 (Worker):

celery -A tasks worker --loglevel=INFO

Terminal 2 (Beat):

celery -A tasks beat --loglevel=INFO

Note: In development, you can run them together using the -B flag, but this is not recommended for production.

celery -A tasks worker --loglevel=INFO -B

Production Considerations

  • Single Instance: You must ensure only one instance of Celery Beat is running at a time, otherwise tasks will be duplicated.
  • Persistence: By default, Beat creates a local file named celerybeat-schedule to keep track of the last run times. Ensure the process has write access to the current directory or configure a specific path.

programming/python/celery