celers-beat
Periodic task scheduler for CeleRS, equivalent to Celery Beat. Schedule tasks to run at regular intervals or specific times using interval or crontab expressions.
Overview
Production-ready task scheduler with comprehensive features:
Core Scheduling:
- ✅ Interval Schedules: Execute every N seconds
- ✅ Crontab Schedules: Unix cron-style scheduling with timezone support
- ✅ Solar Schedules: Sunrise/sunset/twilight/golden hour events
- ✅ One-Time Schedules: Run once at specific time (auto-cleanup)
- ✅ Custom Schedules: User-defined scheduling logic via closures
- ✅ Composite Schedules: Combine schedules with AND/OR logic
Task Management:
- ✅ Persistent State: Track execution history across restarts
- ✅ Schedule Versioning: Track and rollback schedule modifications
- ✅ Task Dependencies: Define execution order with dependency chains
- ✅ Groups & Tags: Organize tasks with hierarchical groups and tags
- ✅ Batch Operations: Efficient bulk add/remove operations
- ✅ Priority Support: High-priority task scheduling
- ✅ Retry Policies: Exponential backoff and fixed delay strategies
Reliability & Monitoring:
- ✅ Crash Recovery: Automatic recovery from scheduler crashes
- ✅ Schedule Locking: Prevent duplicate execution across instances
- ✅ Alerting System: Configurable alerts for failures and performance issues
- ✅ Health Checks: Task health validation and stuck detection
- ✅ Conflict Detection: Analyze overlapping schedules
- ✅ Execution History: Track success/failure/duration statistics
Advanced Features:
- ✅ Calendar Integration: Business hours, holidays, blackout periods
- ✅ Webhook Alerts: Send alerts to external systems
- ✅ Jitter & Catch-up: Avoid thundering herd, handle missed schedules
- ✅ Schedule Indexing: Fast O(log n) due task lookup
Quick Start
Installation
[]
= "0.1"
= { = "0.1", = ["redis"] }
Basic Example
use ;
use RedisBroker;
async
Schedule Types
Interval Schedule
Execute tasks at fixed intervals:
use Schedule;
// Every 10 seconds
let schedule = interval;
// Every 5 minutes
let schedule = interval;
// Every hour
let schedule = interval;
// Every day
let schedule = interval;
Crontab Schedule (Optional)
Unix cron-style scheduling:
[]
= { = "0.1", = ["cron"] }
use Schedule;
// Every minute
let schedule = crontab;
// Every hour at minute 0
let schedule = crontab;
// Every day at midnight
let schedule = crontab;
// Every Monday at 9 AM
let schedule = crontab;
// Weekdays at 9 AM
let schedule = crontab;
Crontab format:
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of week (0-6, 0=Sunday)
│ │ │ ┌───────────── day of month (1-31)
│ │ │ │ ┌───────────── month (1-12)
│ │ │ │ │
* * * * *
Special characters:
*- Any value*/n- Every n units (e.g.,*/15= every 15 minutes)n-m- Range (e.g.,9-17= 9 AM to 5 PM)n,m- List (e.g.,1,15= 1st and 15th)
Solar Schedule (Optional)
Execute tasks at sunrise/sunset:
[]
= { = "0.1", = ["solar"] }
use Schedule;
// Run at sunrise in Tokyo
let schedule = solar;
// Run at sunset in New York
let schedule = solar;
// Run at sunrise in London
let schedule = solar;
Supported events:
"sunrise"- Task runs at sunrise"sunset"- Task runs at sunset
Notes:
- Latitude/longitude must be in decimal degrees
- Times are calculated in UTC
- Next occurrence is searched up to 365 days ahead
Scheduled Tasks
Creating Tasks
use ;
use json;
// Basic task
let task = new;
// Task with arguments
let task = new
.with_args;
// Task with keyword arguments
let mut kwargs = new;
kwargs.insert;
kwargs.insert;
let task = new
.with_kwargs;
// Disabled task (won't run)
let task = new
.disabled;
Task Structure
Beat Scheduler
Basic Usage
use ;
let mut scheduler = new;
// Add tasks
scheduler.add_task;
scheduler.add_task;
// Run scheduler (blocks until shutdown)
scheduler.run.await?;
Managing Tasks
// Add task
scheduler.add_task;
// Remove task
scheduler.remove_task;
// Enable/disable task
scheduler.enable_task;
scheduler.disable_task;
// Get task info
if let Some = scheduler.get_task
// List all tasks
for in scheduler.list_tasks
Persistent Schedules
Load/save schedule state to persist across restarts:
use fs;
// Save state
let state = scheduler.export_state?;
write?;
// Load state
let state = read_to_string?;
scheduler.import_state?;
Configuration Examples
Periodic Reports
// Daily report at midnight
let daily_report = new;
// Weekly report every Monday at 9 AM
let weekly_report = new;
// Monthly report on 1st at midnight
let monthly_report = new;
Maintenance Tasks
// Cleanup every hour
let cleanup = new;
// Database backup daily at 3 AM
let backup = new;
// Log rotation every 6 hours
let rotate_logs = new;
Monitoring Tasks
// Health check every 30 seconds
let health_check = new;
// Metrics collection every 5 minutes
let collect_metrics = new;
// Alert check every minute
let check_alerts = new;
Schedule Builders and Templates
Schedule Builder - Fluent API
Create schedules with a chainable, intuitive API:
use ScheduleBuilder;
// Simple intervals
let schedule = new
.every_n_minutes
.build;
// Business hours only (Mon-Fri, 9 AM - 5 PM)
let schedule = new
.every_n_minutes
.business_hours_only
.build;
// Weekends only
let schedule = new
.every_n_hours
.weekends_only
.build;
// Weekdays with timezone
let schedule = new
.every_n_hours
.weekdays_only
.in_timezone
.build;
// Business hours in Tokyo
let schedule = new
.every_n_minutes
.business_hours_only
.in_timezone
.build;
Builder Methods:
every_n_seconds(n)- Every N secondsevery_n_minutes(n)- Every N minutesevery_n_hours(n)- Every N hoursevery_n_days(n)- Every N daysbusiness_hours_only()- Mon-Fri, 9 AM - 5 PMweekdays_only()- Mon-Friweekends_only()- Sat-Sunin_timezone(tz)- Set timezonebuild()- Create the schedule
Schedule Templates
Pre-built schedules for common patterns:
use ScheduleTemplates;
// Common intervals
every_minute;
every_5_minutes;
every_15_minutes;
every_30_minutes;
hourly;
every_2_hours;
every_6_hours;
every_12_hours;
// Daily schedules
daily_at_midnight;
daily_at_hour; // 3 AM
// Weekly schedules
weekdays_at; // Weekdays at 9:00 AM
weekly_on_monday; // Monday at 9:00 AM
weekend_mornings; // Sat/Sun at 8 AM
// Monthly schedules
monthly_first_day; // 1st of month
monthly_last_day; // 28-31st of month
// Business hours
business_hours_hourly;
business_hours_every_15_minutes;
// Quarterly
quarterly; // Jan/Apr/Jul/Oct 1st
Practical Examples:
// Health check monitoring
let task = new;
// Daily report at 3 AM
let task = new;
// Business hours API sync
let task = new;
// Weekend batch processing
let task = new;
See examples/schedule_builders.rs for comprehensive demonstrations.
Advanced Features
Schedule Versioning
Track and rollback schedule modifications:
use ScheduledTask;
let mut task = new;
// Update schedule (creates version 2)
task.update_schedule;
// Update again (creates version 3)
task.update_schedule;
// Rollback to version 2
task.rollback_to_version?;
// View version history
for version in task.get_version_history
Task Dependencies
Define task execution order with dependency chains:
let extract = new
.with_group;
let transform = new
.with_dependencies
.with_group;
let load = new
.with_dependencies
.with_group;
scheduler.add_task?;
scheduler.add_task?;
scheduler.add_task?;
// Validate dependencies (detects circular dependencies)
scheduler.validate_dependencies?;
// Get dependency chain
let chain = scheduler.resolve_dependency_chain?;
Schedule Locking
Prevent duplicate task execution across multiple scheduler instances:
// Set unique instance ID
scheduler.set_instance_id;
// Try to acquire lock
if scheduler.try_acquire_lock?
Alerting System
Configure alerts for task failures and performance issues:
use AlertConfig;
let alert_config = AlertConfig ;
let task = new
.with_alert_config;
// Register alert callback
scheduler.on_alert;
// Check alerts
scheduler.check_all_alerts;
let critical = scheduler.get_critical_alerts;
Crash Recovery
Automatic recovery from scheduler crashes:
// On restart, detect interrupted tasks
let crashed_tasks = scheduler.detect_crashed_tasks;
// Recover from crash
scheduler.recover_from_crash?;
// Get tasks ready for retry
let retry_tasks = scheduler.get_tasks_ready_for_crash_retry;
Conflict Detection
Detect and analyze overlapping schedules:
// Detect conflicts (tasks scheduled too close together)
let conflicts = scheduler.detect_conflicts?; // 60 second window
// Get high-severity conflicts only
let high_severity = scheduler.get_high_severity_conflicts;
for conflict in high_severity
Groups and Tags
Organize tasks with groups and tags:
let task = new
.with_group
.with_tags;
// Query by group
let reports = scheduler.get_tasks_by_group;
// Query by tag
let daily = scheduler.get_tasks_by_tag;
// Bulk operations
scheduler.enable_group;
scheduler.disable_tag;
Batch Operations
Efficient bulk task management:
// Add multiple tasks in one operation
let tasks = vec!;
scheduler.add_tasks_batch?;
// Remove multiple tasks
scheduler.remove_tasks_batch?;
Schedule Composition
Combine multiple schedules with AND/OR logic:
use CompositeSchedule;
// OR: Run when ANY schedule is due (earliest)
let composite_or = or;
// AND: Run when ALL schedules are due (latest)
let composite_and = and;
Custom Schedules
Define custom scheduling logic:
use CustomSchedule;
let custom = new;
Priority Scheduling
let task = new;
task.options.priority = Some; // Highest priority
Custom Queue
let task = new;
task.options.queue = Some;
Task Expiration
let task = new;
task.options.expires = Some; // Expire after 5 minutes
Conditional Execution
// Check if task is due before running
if task.is_due? else
Production Deployment
Systemd Service
[Unit]
Description=CeleRS Beat Scheduler
After=network.target redis.service
[Service]
Type=simple
User=celery
WorkingDirectory=/opt/celery
ExecStart=/opt/celery/beat
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Docker
FROM rust:1.70 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --bin beat
FROM debian:bullseye-slim
COPY --from=builder /app/target/release/beat /usr/local/bin/
CMD ["beat"]
High Availability
Important: Only run one beat scheduler instance to avoid duplicate task execution!
// Use leader election or singleton pattern
use Mutex;
use Arc;
let lock = new;
// Acquire lock before starting
let _guard = lock.lock.await;
scheduler.run.await?;
Monitoring
Scheduled Task Metrics
// Track execution
for in scheduler.list_tasks
Health Checks
use ;
// Periodic health check
let mut ticker = interval;
loop
Best Practices
1. Single Scheduler Instance
// ❌ Bad: Multiple schedulers (duplicates tasks)
// Worker 1: scheduler.run()
// Worker 2: scheduler.run()
// ✅ Good: Single scheduler instance
// Beat server: scheduler.run()
// Workers: Only execute tasks
2. Persistent State
// Save state on shutdown
use signal;
select!
3. Timezone Handling
// Always use UTC internally
use Utc;
let now = now;
let next_run = schedule.next_run?;
// Convert to local time for display
use New_York;
let local = next_run.with_timezone;
println!;
Comprehensive Timezone Utilities
The crate provides comprehensive timezone utilities for working with schedules across different timezones:
use TimezoneUtils;
// Automatic system timezone detection
let system_tz = detect_system_timezone;
// Validate timezone names
assert!;
// List and search timezones
let all_timezones = list_all_timezones; // 600+ timezones
let us_zones = search_timezones;
// Get current time in multiple timezones
let zones = vec!;
let times = current_time_in_zones;
// Check DST status
let is_dst = is_dst_active?;
// Get UTC offset
let offset = get_utc_offset?;
// Get detailed timezone info
let info = get_timezone_info?;
println!; // Europe/London (UTC+0.0h, GMT, DST: No): ...
// Convert between timezones
let tokyo_time = convert_between_timezones?;
// Get common timezone abbreviations
let abbrevs = get_common_timezone_abbreviations;
let ny_tz = abbrevs.get; // Returns "America/New_York"
// Calculate time until next occurrence in timezone
let duration = time_until_next_occurrence?;
See examples/timezone_utilities.rs for a comprehensive demonstration.
4. Error Handling
// Graceful error handling
loop
5. Task Idempotency
// Ensure tasks are idempotent (safe to run multiple times)
registry.register;
Troubleshooting
Tasks not executing
Check:
- Scheduler is running:
scheduler.is_running() - Task is enabled:
task.enabled == true - Schedule is correct:
task.schedule.next_run() - Broker connection:
broker.ping()
Duplicate executions
Cause: Multiple scheduler instances running Solution: Ensure only one scheduler instance
Missed schedules
Cause: Scheduler was down during scheduled time Solution: Implement catchup logic or use persistent state
Timezone issues
Cause: Mixing UTC and local time Solution: Always use UTC internally, convert for display only
Performance
Scheduling Overhead
| Schedule Type | Overhead | Memory |
|---|---|---|
| Interval | <1ms | ~100B per task |
| Crontab | <5ms | ~200B per task |
| Solar | <10ms | ~300B per task |
Scalability
- Tasks: 10,000+ scheduled tasks
- Precision: 1-second granularity
- Latency: <10ms schedule evaluation
Comparison with Celery Beat
| Feature | Celery Beat | CeleRS Beat |
|---|---|---|
| Interval schedules | ✅ | ✅ |
| Crontab schedules | ✅ | ✅ (with timezone support) |
| Solar schedules | ✅ | ✅ (with twilight & golden hour) |
| One-time schedules | ❌ | ✅ |
| Custom schedules | ❌ | ✅ |
| Schedule versioning | ❌ | ✅ |
| Task dependencies | ❌ | ✅ |
| Crash recovery | ❌ | ✅ |
| Alerting system | ❌ | ✅ |
| Schedule locking | ❌ | ✅ |
| Conflict detection | ❌ | ✅ |
| Business calendars | ❌ | ✅ |
| Persistent state | File/DB | JSON (auto-save) |
| Performance | ~100 tasks/sec | ~1000 tasks/sec |
| Memory | 50MB+ | <10MB |
See Also
- Worker:
celers-worker- Task execution runtime - Broker:
celers-broker-redis- Message broker - Core:
celers-core- Task registry
License
MIT OR Apache-2.0