ChrononImplemented

Scheduled Rust jobs with an operator UI

Chronon schedules cron and run-once jobs with typed script handlers, durable job and run history, and optional coordinator and worker processes.
Run trend, failures and upcoming jobs at a glance.

Why it exists

Chronon keeps schedules and runs in memory, SQLite, Postgres, or Postgres with Redis, and gives each script typed parameters through #[chronon::script]. The same scripts run embedded, or split across coordinator and worker processes. Jobs point at stable script names, each run records its status and timings, and revisions track config changes.

In both templates

Both templates run Chronon next to the product UI, so recurring cleanup and scans share the same Valence-aware context as interactive requests.
Typed scripts
Implemented
Register typed script parameters and handler metadata with #[chronon::script].
Schedules and run history
Implemented
Create cron, manual, and run-once jobs with durable revisions, attempts, status, and timings.
Worker pools and regions
Implemented
Pin a job to a pool and a region. Each worker claims one pool.
Gluon hardware placement
Partially Implemented
Run a pool's workers on a Gluon pool with its own minimum vCPU, memory and disk. The pool names are matched by hand for now.
Scheduler stores
Implemented
Run on memory, SQLite, Postgres, or Postgres with Redis through the SchedulerStore port.
Deployment modes
Implemented
Use embedded, coordinator-only, worker, or remote-coordinator builders without changing script handlers. Coordinators elect a leader, so only one runs the scheduler.
Captured actor context
Implemented
Rebuild execution context from stored actor JSON so scheduled work keeps an explicit identity.
Chronon operator UI
Implemented
Manage jobs and inspect scripts and runs on this host at /chronon.
Worker poolsPartially Implemented

Send heavy jobs to bigger machines

Pin a job to a pool with .pool("ocr"), and to a region with .region("us-east"). Each worker claims the one pool named in CHRONON_WORKER_POOL. On hosts managed by Gluon, the OCR workers can run on 8 vCPU, 32 GB machines while the nightly cleanup stays on small ones. Jobs without a pool run on the default pool, named general.
let job = JobBuilder::new(&ocr_scan())
    .name("ocr-scan")
    .cron("*/15 * * * *")?
    .pool("ocr")
    .region("us-east")
    .build()?;

// On the OCR workers: CHRONON_WORKER_POOL=ocr
Needs Gluon →Gluon doesn't set CHRONON_WORKER_POOL for you yet. Set it to match the Gluon pool the worker runs on.

See it in action

Code sample

Taken from the getting-started docs. See all code samples on Resources.
Chronon jobChronon
Typed #[chronon::script] scheduled with JobBuilder
use std::sync::Arc;
use chronon::prelude::*;
use chronon::InMemorySchedulerStore;

#[chronon::script(name = "nightly_cleanup")]
async fn nightly_cleanup(
    ctx: Box<dyn ScriptContext>,
    retention_days: u32,
) -> chronon::Result<()> {
    println!("{}: retaining {retention_days} days", ctx.label());
    Ok(())
}

#[tokio::main]
async fn main() -> chronon::Result<()> {
    let chronon = Chronon::builder()
        .scheduler_store(Arc::new(InMemorySchedulerStore::new()))
        .context_factory(Arc::new(JsonScriptContextFactory))
        .embedded()
        .auto_registry()
        .build()?;

    let nightly = JobBuilder::new(&nightly_cleanup())
        .name("nightly-schedule")
        .cron("0 2 * * *")?
        .timezone("UTC")
        .params(NightlyCleanupParams { retention_days: 7 })
        .build()?;
    chronon.coordinator_service().upsert_job(nightly).await?;

    chronon.run().await
}