Chronon

Scheduled orchestration from Rust macros to runtime UI

Chronon is a Rust cron and run-once scheduler for services that need typed script handlers, durable job and run history, and an optional coordinator–worker split—without locking into one database or a full workflow engine.

Why this family exists

Most products reinvent cron plus job/run persistence, then couple it to one database or a monolith-only worker. Chronon answers that with a thin SchedulerStore port (mem, SQLite, PostgreSQL, PostgreSQL+Redis), #[chronon::script] typed parameters, and builder assembly for embedded, coordinator, worker, or remote-client topologies. Jobs reference stable script names; each run is one attempt with status and timings; revisions version config changes.

Where it lands

Unified Field schedules Chronon scripts alongside product UI so recurring cleanup, scans, and Gluon scale targets share the same Valence-aware runtime context as interactive requests.
Define scripts with #[chronon::script], upsert Job records with Cron, Manual, or run-once schedules, and let Chronon::builder() wire the store, context factory, and auto-registry. Host ContextFactory reconstructs execution context from stored JSON so identity at schedule time can differ from run time. Representative AWS in-VPC numbers show ~1,000 worker claims/s on postgres-redis hybrids and near-linear multi-cell scaling—methodology lives in chronon-bench. Published as uf-chronon; imports stay use chronon::….

In the workspace

Unified Field schedules Chronon scripts alongside product UI so recurring cleanup, scans, and Gluon scale targets share the same Valence-aware runtime context as interactive requests.

Code sample

From the upstream getting-started docs — see also all code recipes on Resources.
Chronon scriptChronon
Cron job + typed #[chronon::script]
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 mut nightly = Job::new("nightly-schedule", "nightly_cleanup");
    nightly.schedule_kind = ScheduleKind::Cron;
    nightly.cron_expr = Some("0 2 * * *".into());
    nightly.timezone = Some("UTC".into());
    nightly.params_json = serde_json::json!({ "retention_days": 7 });
    chronon.coordinator_service().upsert_job(nightly).await?;

    chronon.run().await
}