Scheduling
Jobs run manually by default. Adding a schedule turns a job into a recurring pipeline — run nightly, hourly, whatever cron expression fits.
For the job definition itself, see Defining jobs. For runs, see Runs & debugging.
Prerequisites
- A saved job. See Defining jobs — schedule fields are part of the job, set on the same edit form.
Set a schedule
On the job's edit form:
- Cron expression — a standard 5-field cron. Leave empty for manual-only. Examples:
0 2 * * *— every day at 2:00 AM*/15 * * * *— every 15 minutes0 9 * * 1— every Monday at 9:00 AM
- Timezone — IANA zone (e.g.
America/New_York,Europe/London). Defaults to UTC. Matters for daily/weekly schedules that should align with business hours and handle DST.
Save the job. If the job is Active, the schedule starts firing at the next matching tick.
Active vs. paused
A job has a status independent of its schedule:
- Active — the schedule fires and produces runs.
- Paused — the definition is intact but no scheduled runs fire. Manual runs still work.
Pause is the first thing to reach for when a job is misbehaving. It's reversible and leaves history intact. Toggle from the job's detail page.
Concurrency policy
The concurrency policy decides what happens if a new tick fires while a previous run hasn't finished.
| Policy | Behavior | Use when |
|---|---|---|
skip | Skip the new tick if any run is still non-terminal | The pipeline is idempotent and overlaps waste compute |
allow | Run in parallel, up to maxConcurrentRuns | Ticks are independent and can safely overlap |
replace | Cancel the running run, start a new one | Only the latest tick matters (e.g. "refresh current state") |
skip is the safest default. Pick allow when you've confirmed overlap is safe, and replace when staleness matters more than completion.
When allow is chosen, set maxConcurrentRuns to cap the blast radius.
Missed-schedule policy
The missed-schedule policy decides what happens if the scheduler was unavailable when a tick should have fired (cluster down, platform incident)?
latest— fire exactly once on recovery, at the recovery time. Right for "keep me current" pipelines where missing ticks is fine as long as the next run catches up.all— fire once per missed tick, with backdated dispatch times. Right for append-only pipelines where every tick matters (e.g. hourly ingest where each hour is a distinct partition).
latest is the default and the right choice most of the time. Pick all only when the workload is a function of the dispatch time, not wall-clock.
Trigger a manual run
From the job's detail page, click Run now. A manual run queues immediately regardless of the schedule. Manual runs on a scheduled job don't affect the schedule — the next cron tick fires as usual.
Schedule hygiene
A few patterns that save pain:
- Avoid
*/1 * * * *(every minute) for anything non-trivial. The control plane and Kubernetes scheduling overhead means ticks pile up. Use sessions for sub-minute work. - Align timezones with the humans who own the pipeline. A job owned by an NYC team should schedule in
America/New_York; DST shifts otherwise cause two runs on one day and zero on another. - Pick concurrency and missed-schedule deliberately. The defaults (
skip+latest) are safe but they mean missed work is lost. If that's not OK for your pipeline, change both.
API reference
- Jobs — schedule fields (
cronExpression,cronTimezone,concurrencyPolicy,maxConcurrentRuns,missedSchedulePolicy) live on the job entity. There's no separate schedule resource.