π¦ Foxtive Cron
A production-ready, asynchronous cron-based job scheduler for Rust powered by Tokio.
Schedule async tasks with cron expressions, manage them dynamically at runtime, control concurrency, handle failures with retry policies, and persist state - all with type-safe guarantees and comprehensive observability.
Features
Cron Expression Builder (NEW in 0.5.0)
- Fluent builder API - Build cron expressions programmatically with type safety
- Type-safe enums -
MonthandWeekdayenums prevent invalid values - Field composition - Intervals, ranges, lists, and single values for all fields
- Common presets -
hourly(),daily(),weekly(),monthly()shortcuts - Timezone support - Schedule jobs in any timezone via
chrono-tz - Blackout dates - Exclude specific dates (holidays, maintenance windows)
- Execution jitter - Add random delays to prevent thundering herd problems
- Compile-time validation - Invalid expressions caught at build time
Core Scheduling
- Standard 7-field cron expressions (with seconds and year support)
- Validated at registration time - no silent runtime failures
- Timezone support via
chrono-tz(schedule in local time, not just UTC) - One-time jobs (run once at specific DateTime)
- Delayed start (recurring jobs with initial delay)
- Per-job priorities (higher priority executes first when concurrent)
Dynamic Job Management
- Add jobs at runtime via
add_job(),add_job_fn(),add_blocking_job_fn() - Remove jobs at runtime via
remove_job(id)- stops execution and cleans up resources - Trigger jobs immediately via
trigger_job(id)without affecting schedule - Introspection API via
list_job_ids()to see all scheduled jobs - Internal job registry for O(1) lookup by ID
Advanced Execution Control
- Global concurrency limits - prevent resource exhaustion
- Per-job concurrency limits - fine-grained control
- Execution timeouts - automatically terminate long-running jobs
- Graceful shutdown - controlled termination with cleanup
- Jobs run concurrently in independent
tokio::spawntasks
Reliability & Resilience
- Misfire policies: Skip, FireOnce, FireAll (handle missed executions)
- Retry strategies: Fixed interval, Exponential backoff (with overflow protection)
- Persistence layer via
JobStoretrait - In-memory store included (
InMemoryJobStore) - State tracking (last run, success/failure counts)
Observability
- Event hooks - listen to lifecycle events (Started, Finished, Failed, Retrying)
- Metrics integration - counters and histograms via
MetricsExportertrait - Structured logging via
tracingcrate - Health checks and monitoring support
Installation
[]
= "0.4"
= { = "1", = ["full"] }
= "1"
= "0.1"
Optional Features
tokio-macros- Enable tokio macros for examples
Quick Start
Using the Cron Expression Builder (Recommended)
use ;
use USEastern;
use Duration;
// Build a cron expression using the fluent API
let schedule = builder
.weekdays_only
.hours_range
.minutes_interval
.with_timezone
.with_jitter
.build;
println!;
// Output: "0 */30 9-17 * * 1-5 *"
Basic async job
use Cron;
async
Blocking job (CPU-intensive)
cron.add_blocking_job_fn?;
Blocking functions run inside tokio::task::spawn_blocking so they never block the async runtime.
With concurrency limit and event listener
use ;
use Arc;
;
let mut cron = builder
.with_global_concurrency_limit // Max 5 concurrent jobs
.with_listener
.build;
cron.add_job_fn?;
Custom Jobs via JobContract
For full control, implement JobContract on your struct:
use ;
use ;
use async_trait;
use Cow;
use Arc;
async
Advanced Features
Retry Policies
use RetryPolicy;
use Duration;
// Fixed retry: retry every 5 seconds, up to 3 times
// Exponential backoff: 2s -> 4s -> 8s -> ... max 60s
Misfire Handling
use MisfirePolicy;
// Skip missed runs if scheduler was down
Skip
// Run once ASAP, then resume normal schedule
FireOnce
// Run all missed executions
FireAll
Timezone Support
use New_York;
// Schedule in local time, not UTC
cron.add_job_fn.timezone?; // Runs at 9:30 AM Eastern Time
Builder API with Advanced Features
use ;
use NaiveDate;
use London;
use Duration;
// Complex schedule with multiple features
let schedule = builder
.weekdays_only // Monday-Friday only
.hours_range // Business hours
.minutes_interval // Every 30 minutes
.with_timezone // London timezone
.with_jitter // Β±60s random delay
.exclude_date // Christmas
.exclude_date // Boxing Day
.build;
println!;
Common Builder Patterns
// Daily backup at 2:30 AM
let daily_backup = builder
.daily
.hour
.minute
.build;
// Health check every 30 seconds
let health_check = builder
.seconds_interval
.build;
// Monthly report on 1st at 9 AM
let monthly_report = builder
.monthly
.hour
.build;
// Multiple specific times per day
let digest_emails = builder
.daily
.hours_list // 8 AM, 12 PM, 6 PM
.minute
.build;
Graceful Shutdown
let mut cron = new;
// ... add jobs ...
// Gracefully shutdown - waits for running jobs to complete
cron.shutdown.await;
Cron Expression Format
Foxtive Cron uses a 7-field cron format:
sec min hour day month weekday year
| Example | Meaning |
|---|---|
*/10 * * * * * * |
Every 10 seconds |
0 * * * * * * |
Every minute |
0 0 * * * * * |
Every hour |
0 30 9 * * * * |
Every day at 09:30:00 |
0 0 0 1 * * * |
First day of every month |
0 0 0 * * MON-FRI * |
Monday to Friday at midnight |
Expressions are validated via ValidatedSchedule::parse() at registration time.
Invalid expressions return Err immediately rather than failing silently at runtime.
Thread Safety & Concurrency
- Jobs execute in independent
tokio::spawntasks - slow jobs never block others - Multiple jobs due at the same tick fire concurrently in the same iteration
- Jobs wrapped in
Arc<dyn JobContract>must beSend + Sync - Global concurrency limits prevent resource exhaustion
- Per-job concurrency limits for fine-grained control
- Priority-based execution when multiple jobs are due simultaneously
Logging & Observability
Job execution is traced via the tracing crate:
INFOlevel: Job start and successful completionERRORlevel: Job failures (scheduler continues running)WARNlevel: Misfires, retries, and warnings
Integrate with any tracing-compatible subscriber:
use tracing_subscriber;
fmt
.with_max_level
.init;
Custom Event Listeners
Implement JobEventListener to receive real-time notifications of all job lifecycle events.
Examples
See the examples/ directory for complete working examples:
Builder API Examples (NEW)
- builder_basic.rs - Comprehensive cron expression builder demonstrations
- builder_real_world_scenarios.rs - Production-ready scheduling patterns
- builder_timezone_advanced.rs - Advanced timezone-aware scheduling
- builder_blackout_and_jitter.rs - Blackout dates and jitter strategies
- builder_complex_composition.rs - Complex field composition patterns
- builder_devops_automation.rs - DevOps and infrastructure automation
- builder_edge_cases.rs - Edge cases and validation scenarios
Core Features
- basic.rs - Simple job scheduling
- advanced.rs - Custom jobs with full lifecycle hooks
- concurrency.rs - Managing concurrent job execution
- persistence.rs - Persisting job state with InMemoryJobStore
- priority.rs - Job priority handling
- timezone.rs - Scheduling in different timezones
Run examples with:
# ... etc
Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cron Scheduler β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ β
β β Job Registry β β Priority Queueβ βSemaphoresβ β
β β (HashMap) β β (BinaryHeap) β β β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Job Execution Engine β β
β β β’ Concurrency Control β β
β β β’ Retry Logic β β
β β β’ Misfire Handling β β
β ββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ β
β βEvent Listenersβ βMetrics Exportβ βJob Store β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key components:
- Job Registry: O(1) lookup by job ID
- Priority Queue: Efficient scheduling via BinaryHeap (min-heap by next_run)
- Semaphores: Concurrency control (global and per-job)
- Event System: Real-time lifecycle notifications
- Metrics: Counters and histograms for monitoring
- Persistence: Pluggable storage backends
Contributing
Contributions, bug reports, and feature requests are welcome!
To contribute:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Ensure all tests pass:
cargo test - Check for clippy warnings:
cargo clippy - Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
License
MIT License