Skip to content

Schedules & windows

A workflow’s schedule decides when occurrences happen; each occurrence anchors the evaluation window its queries run over. By default, consecutive windows tile time exactly (no gaps, no double counting), and every server instance computes the same occurrence times.

Cadences

{ "schedule": { "every": "5m", "delay": "30s" } }

every is an interval ("1m", "5m", "1h") or a calendar cadence. An interval must divide a day evenly ("30s", "5m", "45m", "6h") or be a whole number of days ("2d"); validation refuses "7m", "5h" or "36h". Interval occurrences are multiples of the interval since the unix epoch, so two server instances compute identical occurrence times, and each occurrence is a bucket start of a dashboard query at the same interval. A calendar cadence reads as a sentence:

{
"schedule": {
"every": { "week": { "on": "monday", "at": "07:00" } },
"timezone": "Europe/Amsterdam"
}
}

day, week, and month cadences resolve in timezone (set it explicitly when instances in different regions share a project). A day of the month the month does not have clamps to its last day, so 31 means “month’s end”. schedule: false declares a workflow with no schedule; it never runs today (UI and API triggers are planned).

The evaluation window

Each occurrence’s window spans back to the previous occurrence: a 5m workflow evaluated at 12:05 sees 12:00 → 12:05, and the 12:10 occurrence sees 12:05 → 12:10. The window seeds the run’s time range, and a query over the borrowed view binds to it, so count(*) in an evaluation counts one window’s worth every time.

delay shifts both window bounds back. With delay: "30s", the 12:05 occurrence is due at 12:05 and evaluates 11:59:30 → 12:04:30; the 30 seconds give telemetry still in flight through collectors and inserts time to land. Windows still tile exactly. If your workflows see partial data at the window’s trailing edge, raise delay instead of widening queries.

Phase

An interval cadence also has a phase: a fixed offset shorter than the interval and shorter than 15 minutes, computed from a hash of the workflow reference. A run starts once the occurrence plus the phase has passed. Workflows with the same cadence therefore start at different points in the interval. This keeps the query load on the database even. Every server instance computes the same phase, and it stays the same across restarts, so one workflow’s runs remain one interval apart.

The phase only moves the start of the run. The occurrence and its window stay the same: with every: "5m", delay: "30s", and a phase of 2m10s, the 12:05 occurrence runs at 12:07:10 and evaluates 11:59:30 → 12:04:30. A workflow’s results therefore arrive up to 15 minutes after the occurrence, and never later than the next occurrence. Calendar cadences have no phase and run at their authored time. Each run record carries its phase as run.phase_ms.

Set schedule.phase to choose the phase yourself. spread takes a phase from the hash, shorter than max:

{ "schedule": { "every": "1d", "phase": { "spread": { "max": "5m" } } } }

Omitting max spreads over the interval or 15 minutes, whichever is shorter. On a calendar cadence, { "spread": {} } spreads over 15 minutes.

fixed starts every run a set time after its occurrence, and "0s" starts runs at the occurrence:

{ "schedule": { "every": "5m", "phase": { "fixed": "0s" } } }

Workflows that share a fixed phase start together.

A phase at or above the interval is allowed. Each run then starts after the next occurrence, and results arrive that much later.

Explicit lookback

Set schedule.window to evaluate a different duration from the execution cadence:

{ "schedule": { "every": "1m", "window": "5m", "delay": "30s" } }

Each run evaluates five minutes of data while runs occur every minute. Consecutive windows overlap; use this for rolling evaluations. Omit window for extraction or rollups that need consecutive windows without counting the same data twice. The existing delay shifts the trailing bound and defers dispatch as described above. Changing the lookback does not change occurrence times. Identity detectors use the scheduling interval when converting occurrence counts to durations for grace validation and initial seeding. Each run pins that interval alongside its query bounds, including calendar intervals across daylight saving time.

Catch-up after downtime

When occurrences were missed (a laptop asleep, a server down), catch_up decides what runs:

  • { "latest": {} } (default) — run only the newest due occurrence, against its own window. The usual choice for alerting workflows, where evaluating a stale window has no value.
  • { "backfill": { "limit": 12 } } — also run the limit most recent missed occurrences, oldest first, each against its own window; older ones are skipped. For computations where every window matters, SLO math being the canonical case.

A schedule that has never run owes only its newest occurrence; history from before the workflow existed is not backfilled.