SchedulerConfig¶
Configure task scheduling in your Ravyn application for running background jobs and periodic tasks.
What You'll Learn¶
- What task scheduling is
- Configuring the scheduler
- Creating scheduled tasks
- Common scheduling patterns
Quick Start¶
from ravyn import Ravyn
from ravyn.config import SchedulerConfig
app = Ravyn(
scheduler_config=SchedulerConfig(
enabled=True
)
)
Info
Install scheduler support: pip install ravyn[schedulers] or pip install asyncz
What is Task Scheduling?¶
Task scheduling allows you to run functions automatically at specific times or intervals. Perfect for:
-
Periodic Tasks - Run every hour, day, week
-
Cleanup Jobs - Delete old data regularly
-
Data Sync - Sync with external APIs
-
Reports - Generate daily/weekly reports
-
Monitoring - Health checks and alerts
Basic Configuration¶
Minimal Setup¶
from ravyn import Ravyn
from ravyn.config import SchedulerConfig
app = Ravyn(
scheduler_config=SchedulerConfig(
enabled=True
)
)
Complete Configuration¶
app = Ravyn(
scheduler_config=SchedulerConfig(
enabled=True,
timezone="UTC",
max_instances=3,
coalesce=True
)
)
Configuration Parameters¶
| Parameter | Type | Description | Default |
|---|---|---|---|
enabled |
bool | Enable scheduler | False |
timezone |
str | Timezone for tasks | "UTC" |
max_instances |
int | Max concurrent instances | 1 |
coalesce |
bool | Combine missed runs | False |
Creating Scheduled Tasks¶
Using @scheduler Decorator¶
from ravyn import Ravyn
from ravyn.config import SchedulerConfig
from ravyn.contrib.schedulers.asyncz.decorator import scheduler
app = Ravyn(
scheduler_config=SchedulerConfig(enabled=True)
)
@scheduler(name="cleanup_task", trigger="interval", hours=1)
async def cleanup_old_data():
"""Run every hour."""
await delete_old_records()
print("Cleanup completed")
Cron-Style Scheduling¶
@scheduler(
name="daily_report",
trigger="cron",
hour=9,
minute=0
)
async def generate_daily_report():
"""Run every day at 9:00 AM."""
report = await create_report()
await send_email(report)
Trigger Types¶
Interval Trigger¶
Run at fixed intervals:
# Every 30 minutes
@scheduler(name="sync", trigger="interval", minutes=30)
async def sync_data():
await sync_with_api()
# Every 2 hours
@scheduler(name="backup", trigger="interval", hours=2)
async def backup_database():
await create_backup()
# Every day
@scheduler(name="cleanup", trigger="interval", days=1)
async def daily_cleanup():
await cleanup()
Cron Trigger¶
Run at specific times:
# Every day at 3:00 AM
@scheduler(name="backup", trigger="cron", hour=3, minute=0)
async def nightly_backup():
await backup_database()
# Every Monday at 9:00 AM
@scheduler(name="report", trigger="cron", day_of_week="mon", hour=9)
async def weekly_report():
await generate_report()
# Every 1st of month at midnight
@scheduler(name="billing", trigger="cron", day=1, hour=0)
async def monthly_billing():
await process_billing()
Date Trigger¶
Run once at a specific date/time:
from datetime import datetime
@scheduler(
name="campaign",
trigger="date",
run_date=datetime(2026, 12, 31, 23, 59)
)
async def end_campaign():
await close_campaign()
Common Patterns¶
Pattern 1: Database Cleanup¶
@scheduler(name="cleanup", trigger="cron", hour=2, minute=0)
async def cleanup_old_sessions():
"""Delete old sessions every day at 2 AM."""
from datetime import datetime, timedelta
cutoff = datetime.utcnow() - timedelta(days=30)
await Session.filter(created_at__lt=cutoff).delete()
print(f"Cleaned up sessions older than {cutoff}")
Pattern 2: API Sync¶
@scheduler(name="sync_users", trigger="interval", minutes=15)
async def sync_users_from_api():
"""Sync users every 15 minutes."""
import httpx
async with httpx.AsyncClient() as client:
response = await client.get("https://api.example.com/users")
users = response.json()
for user_data in users:
await User.update_or_create(
id=user_data["id"],
defaults=user_data
)
Pattern 3: Report Generation¶
@scheduler(name="daily_report", trigger="cron", hour=8, minute=0)
async def send_daily_report():
"""Send daily report at 8 AM."""
# Generate report
stats = await calculate_daily_stats()
# Send email
await send_email(
to="admin@example.com",
subject="Daily Report",
body=f"Stats: {stats}"
)
Using with Settings¶
from ravyn import RavynSettings
from ravyn.config import SchedulerConfig
class AppSettings(RavynSettings):
scheduler_config: SchedulerConfig = SchedulerConfig(
enabled=True,
timezone="America/New_York",
max_instances=3
)
app = Ravyn(settings_module=AppSettings)
Advanced Features¶
Multiple Instances¶
# Allow up to 3 concurrent instances
@scheduler(
name="heavy_task",
trigger="interval",
minutes=5,
max_instances=3
)
async def heavy_processing():
await process_large_dataset()
Coalescing¶
# If missed runs, execute only once
@scheduler(
name="sync",
trigger="interval",
minutes=10,
coalesce=True
)
async def sync_data():
await sync_with_external_api()
Conditional Execution¶
@scheduler(name="backup", trigger="cron", hour=3)
async def conditional_backup():
"""Only backup if data changed."""
if await has_data_changed():
await create_backup()
else:
print("No changes, skipping backup")
Best Practices¶
1. Use Appropriate Intervals¶
# Good - reasonable intervals
@scheduler(name="health_check", trigger="interval", minutes=5)
async def health_check():
pass
# Wrong - too frequent
@scheduler(name="check", trigger="interval", seconds=1)
async def constant_check():
pass
2. Handle Errors Gracefully¶
# Good - error handling
@scheduler(name="sync", trigger="interval", hours=1)
async def sync_with_retry():
try:
await sync_data()
except Exception as e:
logger.error(f"Sync failed: {e}")
# Maybe retry or alert
3. Use Timezone Aware Times¶
# Good - explicit timezone
app = Ravyn(
scheduler_config=SchedulerConfig(
enabled=True,
timezone="America/New_York"
)
)
Common Pitfalls & Fixes¶
Pitfall 1: Forgot to Enable¶
Problem: Scheduler not running.
# Wrong - scheduler disabled
app = Ravyn() # enabled=False by default
Solution: Enable scheduler:
# Correct
app = Ravyn(
scheduler_config=SchedulerConfig(enabled=True)
)
Pitfall 2: Missing Dependencies¶
Problem: Import error.
# Wrong - asyncz not installed
ModuleNotFoundError: No module named 'asyncz'
Solution: Install dependencies:
# Correct
pip install ravyn[schedulers]
# or
pip install asyncz
Pitfall 3: Blocking Operations¶
Problem: Using sync code in async task.
# Wrong - blocking operation
@scheduler(name="task", trigger="interval", minutes=5)
async def blocking_task():
time.sleep(60) # Blocks event loop!
Solution: Use async operations:
# Correct
@scheduler(name="task", trigger="interval", minutes=5)
async def async_task():
await asyncio.sleep(60) # Non-blocking
Next Steps¶
- LoggingConfig - Application logging
- Lifespan Events - Application lifecycle
- Background Tasks - One-off tasks