Skip to content

Run a task on a schedule

Goal: run some work on a fixed schedule — a nightly sweep, an hourly refresh — without an incoming request.

Cron handlers go in a service inside a context. Each names a schedule (bare, after cron), takes at most one parameter, and returns Effect[Result[(), E]].

context reaper
service sweeper from cron {
on schedule("*/5 * * * *") () -> Effect[Result[(), String]] {
Ok(())
}
}

The schedule is a standard five-field cron expression (minute hour day-of-month month day-of-week). */5 * * * * runs every five minutes; 0 0 * * * runs at midnight.

Cron has no built-in clock. To learn when the run fired, declare a single Int parameter — it receives the scheduled time as Unix epoch milliseconds. It is the exact, schedule-aligned instant (better than “now” for bucketing or idempotency keys):

context reaper
service sweeper from cron {
on schedule("0 * * * *") (at: Int) -> Effect[Result[(), String]] {
Ok(())
}
}

Return Ok(()) when the run succeeds. A cron run has no caller to answer and no retry, so a failure is returned as Err(e) — it is logged and the run completes. Map a domain error to Err explicitly:

type SweepError = enum { StorageUnavailable }
service sweeper from cron {
on schedule("0 0 * * *") () -> Effect[Result[(), SweepError]] {
Err(StorageUnavailable)
}
}

Cron services compile to a Cloudflare Worker with --target workers; each schedule lands in the [triggers] table of the generated wrangler.toml. See Target Cloudflare Workers.

  • Reference: Cron.
  • Reference: HTTP — the sibling request-driven handler.