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
crontabfile 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:
- The Worker: Executes the tasks.
- 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-scheduleto keep track of the last run times. Ensure the process has write access to the current directory or configure a specific path.