Flow SDK
Scheduled Jobs
Configure cron-based execution for SDK artifacts — cron expression syntax, timezone handling, concurrency controls, and failure recovery.
A scheduled job runs an artifact on a recurring schedule. Manage jobs at SDK → Scheduled Jobs. You can attach multiple schedules to the same artifact — for example, one every 5 minutes in production and once daily in staging.
Cron Expression Syntax
FlowOS uses 5-field POSIX cron with an optional seconds field:
bash
# Standard 5-field (minute precision)
┌───────────── minute (0–59)
│ ┌─────────── hour (0–23)
│ │ ┌───────── day of month (1–31)
│ │ │ ┌─────── month (1–12 or JAN–DEC)
│ │ │ │ ┌───── day of week (0–7 or SUN–SAT, 0 and 7 = Sunday)
│ │ │ │ │
* * * * *
# Optional 6-field (second precision — prefix with seconds field)
┌─────────────── second (0–59)
│ ┌───────────── minute (0–59)
│ │ ┌─────────── hour (0–23)
...Common Expressions
| Expression | Meaning |
|---|---|
| */5 * * * * | Every 5 minutes |
| 0 * * * * | Every hour on the hour |
| 0 8 * * 1-5 | Weekdays at 8:00 AM |
| 0 9 * * MON | Every Monday at 9:00 AM |
| 30 6 1 * * | 1st of every month at 6:30 AM |
| 0 0 * * 0 | Every Sunday at midnight |
| 0 */6 * * * | Every 6 hours |
| 15 14 1 1 * | January 1st at 14:15 |
| 0 8,12,17 * * 1-5 | Weekdays at 8am, noon, and 5pm |
| 0 9 * * 1 | Every Monday at 9am |
| 30 */2 * * * | Every 2 hours, at :30 |
Named Schedules
You can use shorthand names instead of cron expressions:
| Name | Equivalent |
|---|---|
| @yearly | 0 0 1 1 * — January 1st at midnight |
| @monthly | 0 0 1 * * — 1st of each month at midnight |
| @weekly | 0 0 * * 0 — Sunday at midnight |
| @daily | 0 0 * * * — Midnight every day |
| @hourly | 0 * * * * — Start of every hour |
| @every 5m | Every 5 minutes (Go duration syntax: 30s, 15m, 2h) |
Job Configuration
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| name | string | required | — | Display name for this job. |
| artifact | string | required | — | Artifact slug to run. |
| schedule | string | required | — | Cron expression or named schedule. |
| timezone | string | optional | UTC | IANA timezone string. Schedule is interpreted in this timezone. |
| environment | enum | required | — | development | staging | production. Job runs in this environment. |
| input | object | optional | — | Static input object passed to the artifact as ctx.trigger.payload. |
| timeout | number | optional | 30 | Override artifact default timeout (seconds). |
| concurrency | enum | optional | "skip" | What to do if previous run is still active: skip | queue | cancel_previous |
| retry_on_failure | boolean | optional | false | Retry once on failure. |
| retry_delay_sec | number | optional | 60 | Seconds to wait before retry. |
| notify_on_failure | object | optional | — | { channel, to, template } — send alert when job fails. |
| enabled | boolean | optional | true | Toggle without deleting. |
Trigger Payload
Inside the artifact, access schedule context via ctx.trigger.payload:
typescript
export async function run(ctx: NodeContext) {
const { scheduledAt, jobName, runNumber, environment } = ctx.trigger.payload as {
scheduledAt: string // ISO 8601 timestamp of the scheduled fire time
jobName: string // e.g. "daily-sla-report"
runNumber: number // monotonically increasing per job
environment: string // "production"
}
ctx.log.info('Job fired', { scheduledAt, runNumber })
}Concurrency Modes
- •
skip(default) — If the previous run is still executing when the next fire time arrives, skip this fire. Logged asskippedin the execution log. - •
queue— Queue the new run. It starts as soon as the previous one completes. Useful for jobs where every run must execute but order matters. - •
cancel_previous— Immediately cancel the running execution and start a fresh one. Use for idempotent jobs where having a stale run is worse than missing data.
Minimum schedule interval is 30 seconds. Jobs with intervals shorter than their typical execution time will accumulate in queue mode — use
skip or cancel_previous for fast-interval jobs.Manual Trigger & Backfill
Trigger a job immediately from the UI (SDK → Scheduled Jobs → [job] → Run Now) or via CLI:
bash
# Trigger once immediately
flowos job trigger daily-sla-report --env production
# Backfill missed runs for a time range
flowos job backfill daily-sla-report --from 2026-05-01 --to 2026-05-31 --env production