We're dsplce.co, check out our work on our website: dsplce.co π€
relayr
πββοΈ Effortless delegated cron jobs β scheduled tasks in Rust, made simple.
relayr lets you register cron jobs across your codebase without the manual boilerplate. Annotate a function with a macro and it gets auto-discovered and scheduled at runtime β no central list to keep in sync, no giant match block to grow.
This crate is a wrapper around async-cron-scheduler to use it in a delegated flavour. If you're not after the delegated way of defining your cron jobs, you're probably better off using that directly.
βΈ»
π€ Features
- One macro is the whole registration. Slap
#[cron("...")]on a function and you're done β define the job right where it lives, not in some central registry you'll forget to update. - No manual wiring. Jobs are discovered at compile time via
inventory, so there's no match block and no "ah, I forgot to add it to the list". - Typos fail the build, not prod. Literal cron patterns are validated at compile time β a malformed schedule won't sneak past you to surface at 3am.
- Fully async. Built on top of
tokio; your jobs are plainasync fns. - Schedules from the environment. Point a job at an env var instead of a literal and change its cadence without a recompile.
- One callback catches everything. Register a single error handler and whatever any job throws lands there.
- Timezone-aware. Run under
Local,Utc, or anychrono-tzzone.
βΈ»
Table of Contents
- π€ Features
- π¦ Installation
- π§ͺ Usage
- π οΈ Requirements
- π Repo & Contributions
- π License
βΈ»
π¦ Installation
Add it with cargo:
Or drop it into your Cargo.toml by hand:
= "0.4"
That pulls in the core scheduler, inventory, and the macro support β nothing else to wire up.
βΈ»
π§ͺ Usage
Define a job
Annotate any async fn that takes a JobId and returns anyhow::Result<()>. The cron pattern accepts an optional leading seconds field, so 1/1 * * * * * means "every second":
use *;
use Local;
async
async
That's it. When relayr::run() starts it picks up every function decorated with #[cron(...)] and schedules it β no registration step, no boilerplate. Swap Local for Utc or any chrono-tz zone to run on a different timezone.
Schedule from an environment variable
Sometimes you don't want the cadence baked into the binary β staging should sweep hourly, prod every five minutes, that sort of thing. Pass a bare identifier (an env var name) instead of a string literal, and relayr resolves the pattern at runtime:
use *;
// reads the cron pattern from the CLEANUP_SCHEDULE environment variable at startup
async
One caveat worth knowing: literal patterns are validated at compile time, but env-var ones can only be checked once the value is read β so if CLEANUP_SCHEDULE is unset or malformed when relayr::run() starts, it'll panic rather than silently skip the job.
Handle errors with a callback
Jobs return a Result, and each one runs in its own task β so a single job blowing up never takes the scheduler (or the others) down with it. Register one callback before run() and every error lands there, tagged with the job's id and name:
use *;
use Local;
async
async
job_name is the function's name, so you get readable logs for free without naming anything twice.
How it works
- You annotate functions with
#[cron("cron pattern")](or#[cron(ENV_VAR_NAME)]). - Under the hood the macro registers your function in a global
inventory. - When
relayr::run::<Tz>()is called, it:- spins up a scheduler for the timezone you pass,
- iterates over every discovered job,
- resolves each pattern (literal or from the environment) and inserts it.
No manual wiring. No giant match blocks. Just clean, delegated jobs.
βΈ»
π οΈ Requirements
- Rust (2024 edition):
relayruses the 2024 edition, so a reasonably recent toolchain is needed. - An async runtime: jobs run on
tokio, which comes bundled as a dependency β you just need#[tokio::main](or your own runtime) at the entry point.
βΈ»
π Repo & Contributions
π οΈ Repo: https://github.com/dsplce-co/relayr π¦ Crate: https://crates.io/crates/relayr
PRs welcome! Let's make scheduled Rust β¨clean and effortless.
βΈ»
π License
MIT or Apache-2.0, at your option.