Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt

Use this file to discover all available pages before exploring further.

The Flow Scheduler fires due pipelines from their ir.schedule. It runs in-process by default via a 60-second setInterval registered in instrumentation.ts on server startup, so kaireon ships complete out of the box — no external cron service required. The same dispatch logic is also exposed as the /api/v1/cron/flow-scheduler-tick HTTP endpoint for self-hosters who prefer their own orchestrator (k8s CronJob, EventBridge, Vercel Cron, etc.). Multi-replica safety comes from a pg advisory lock — only one replica or HTTP caller’s tick runs at a time per minute, the rest no-op with {skipped: true}.

Configuration

Env varDefaultPurpose
CRON_SECRETrequiredShared secret for both the in-process ticker and the HTTP endpoint. The internal scheduler refuses to start if unset (logged warning)
FLOW_INTERNAL_SCHEDULER_ENABLEDtrueSet to "false" to disable in-process ticking — useful when you bring your own external scheduler
FLOW_SCHEDULER_INTERVAL_MS60000Tick interval in milliseconds. Minimum 1000
FLOW_INTERNAL_SCHEDULER_BASE_URLhttp://127.0.0.1:${PORT}Where the in-process ticker fans out run-dispatch fetches
PORT3000Server port used to default the in-process scheduler base URL

Manual tick from the editor

The Schedule tab inside the pipeline editor has a Tick scheduler now button that hits the HTTP endpoint with the same-origin session cookie. Useful when you’ve just saved a schedule and want to fire it without waiting for the next minute boundary.

Endpoint

GET /api/v1/cron/flow-scheduler-tick
Authorization: Bearer $CRON_SECRET
(Or pass x-cron-secret: $CRON_SECRET header.) Auth: Fails closed when CRON_SECRET env is unset (matches the contract of /api/v1/cron/approvals-expire and other cron routes). Response:
{
  "tickAt": "2026-04-27T20:00:00.000Z",
  "totalPipelines": 47,
  "scheduled": 12,
  "due": 3,
  "dispatched": 3,
  "failed": 0,
  "results": [
    { "pipelineId": "...", "tenantId": "...", "fired": true, "status": 201 }
  ],
  "durationMs": 412
}

Per-kind decision logic

Implemented as a pure due-pipelines helper in the platform’s flow scheduling module — given the current set of schedules and the tick time, it returns the IDs that fire on this tick.
Kind”Due” condition
croncron-parser yields any occurrence in (lastRunAt, now] (most recent wins)
intervalnow - lastRunAt >= minutes * 60_000
rruleRRule.between(lastRunAt, now) returns ≥ 1 occurrence
lastRunAt = null (pipeline never ran): treated as 24h lookback to avoid stampeding old, never-run pipelines that were created days/weeks ago. Bad schedules (malformed cron, malformed rrule) silently skip the pipeline — parsePipelineIR would have rejected the IR save earlier anyway.

How it fires

Default (in-process): The scheduler is self-firing. A setInterval registered by Next.js’ instrumentation hook on server boot calls the same dispatch path every 60 seconds via the platform’s internal-ticker module. No external orchestrator required. App Runner and any persistent-container deployment Just Work. Optional (external): If you set FLOW_INTERNAL_SCHEDULER_ENABLED=false (e.g. you’re on a serverless runtime with no persistent process), wire any external scheduler to the HTTP endpoint:
SetupApproach
Self-hosted (k8s)A Kubernetes cron job resource hitting /api/v1/cron/flow-scheduler-tick every minute
Self-hosted (Linux box)* * * * * curl -fsSL -H "x-cron-secret: $CRON_SECRET" https://your-app/api/v1/cron/flow-scheduler-tick
AWSEventBridge Schedule → API destination
VercelA Vercel Cron Job (vercel.json crons array) hitting the endpoint

Idempotency

  • Calling the endpoint multiple times in one minute does not double-fire a pipeline — once a run is dispatched, lastRunAt advances to the fire time, and the next tick’s (lastRunAt, now] window excludes the same occurrence.
  • Per-tick fanout is O(n) over all IR-native pipelines + 1 IR fetch each. Phase 6.6 hardening adds an index + a “schedule_only” projection.

Honest limits

  • Per-tenant scheduler dashboard showing miss / lag / failed dispatches
  • trigger.file_arrival.deadline.{windowMinutes, onMiss} enforcement — currently only pure schedule kinds fire; deadline windows on file_arrival triggers are not yet checked
  • Push-based file-arrival triggers (S3 ObjectCreated, SFTP fanotify, inotify) are not yet implemented; today the source node’s waitPolicy provides pull-based file-arrival behavior