RunAt
A distributed job scheduler for Rust with PostgreSQL backend support.
Features
- Distributed Job Scheduling: Run jobs across multiple workers with PostgreSQL-backed coordination
- Cron Support: Schedule recurring jobs using cron expressions
- Retry Mechanisms: Built-in exponential backoff and custom retry strategies
- Type-Safe Jobs: Leverage Rust's type system for job definitions
- Async/Await: Built on Tokio for efficient async job execution
Installation
Add this to your Cargo.toml:
[]
= "0.2.0"
For PostgreSQL support (enabled by default):
[]
= { = "0.2.0", = ["postgres"] }
Optional features:
postgres- PostgreSQL backend (enabled by default)tracing- Tracing support for observability
Quick Start
Basic Job
use ;
use PgPoolOptions;
use Arc;
use async_trait;
use ;
// Define your job struct
// Implement the job logic
async
Scheduled Jobs with Cron
// Register the job handler first
queue.?;
// Schedule a job to run every 10 seconds
queue.enqueue.await?;
Custom Job Implementation
use ;
use ;
use async_trait;
// Don't forget to register before using
// queue.register::<ProcessPayment>()?;
Job Registration
Important: You must register job handlers with the queue before workers can process them. Each queue instance has its own registry.
// Register all job types your workers will process
queue.?;
queue.?;
queue.?;
// Then start your workers
queue.start_worker.await?;
If a worker encounters a job type that hasn't been registered, it will fail the job with a helpful error message:
No handler registered for job type: SendEmailJob. Call queue.register::<T>() before starting workers.
Running Workers
You can run workers in two ways:
Option 1: Run worker directly from the queue (recommended)
// JobQueue is Clone, so you can clone it before moving into the task
let queue_clone = queue.clone;
spawn;
Option 2: Create a worker instance
use JobWorker;
// Create a worker from the queue
let worker = queue.worker;
// Run the worker
spawn;
Retry Strategies
use Retry;
use Duration;
// Create a job with exponential backoff retry
let mut job = new?;
job.max_attempts = 5;
job = job.retry;
queue.enqueue.await?;
Running Tests