wikis / Cloudflare OS / wiki / entities / gatekeeper-scheduler.md view as markdown report a mistake
Overview
Scheduled Tasks (Scheduler) is an ambient gatekeeper — it doesn't connect to an external service but lets workspace code register persistent callbacks for elapsed intervals, wall-clock recurrences, and one-time runs. Each account also gets a read-only management app at /gatekeepers/scheduler for searching and inspecting schedules across the account.
Characteristics
- No external auth — it is capability-authorized rather than identity-authorized: it does not receive Workshop user identity, assert its own ambient policy, or expose external network authority. Workshop's hook admission and observation authorization remain the security boundaries.
- Agent API (
ScheduleSession, full contract insrc/types.d.ts) exposes three registration methods:every(everyMs, callback, options)— elapsed UTC time; minimum interval 60 seconds.calendarAt(rule, callback, options)— local wall-clock time, requires explicit IANA timezone; supports hourly/daily/weekly rules.runAt(when, callback, options)— runs once at an absolute epoch-ms timestamp or timezone-aware wall-clock time. Example:
const callback = await ctx.restore({ type: "dailyBrief" }); const scheduleId = await SCHEDULER.calendarAt( { timeZone: "America/Chicago", freq: "weekly", byDay: ["MO","TU","WE","TH","FR"], hour: 8, minute: 0 }, callback, { title: "Daily brief", description: "Prepare the morning calendar and inbox brief.", occurrences: { count: 10 } }, ); - Bounds: recurring calls take
occurrences: { count: N }oroccurrences: { until: {...} }(never both);runAt()accepts neither. Count bounds due slots, not successful runs — a slot consumes one count as soon as due, even if admission/delivery fails. - Callbacks implement
ScheduledTaskHook.onSchedule()and must be made persistent viactx.restore()before registration. Each firing carriesscheduleId,runId(stable across retries — use as idempotency key),scheduledTime,actualTime,timeZone. Failures retry up to 8 total attempts with exponential delay (starts at 1 minute, caps at 1 hour); exhausted schedules enter Needs attention. - Lifecycle: registration only binds a disabled hook (writes no schedule row); enabling it in the Connections UI creates the account-driver row and arms the alarm; disabling removes the row/capabilities; re-enabling creates fresh active state but preserves recurrence phase (no catch-up of missed work). Disconnecting the Scheduler account revokes its driver, deletes state, and leaves a tombstone.
- Architecture: one SQLite-backed
ScheduleDriverDurable Object and one alarm per account, covering all its workspaces. The alarm processes at most 20 due schedules per pass with 4 concurrent deliveries, persists state before crossing RPC boundaries, and uses stablerunIdfencing. - Limits (fixed policy, not deployment settings): 500 enabled/terminal schedule rows per account; 100 per workspace; 100 rows per management page; 20 due schedules per alarm pass / 4 concurrent deliveries; 8 callback attempts per occurrence; titles 200 chars, descriptions 2,000 chars.
- Deployment requirement: the
allow_irrevocable_stub_storagecompatibility flag is required while stored callback capabilities exist and must not be removed from an existing deployment. AddGATEKEEPER_SCHEDULERto the deployment's Workshop service bindings; vendor provisioning defaults tooptional.
How to Use
- Ask the agent to create a scheduled task, or open Scheduled and choose a starter prompt; confirm cadence and IANA timezone (for wall-clock schedules) with the user explicitly — never infer timezone from locale.
- The agent registers a persistent callback (
every,calendarAt, orrunAt), which returns a schedule ID but leaves the hook disabled. - Enable the hook in the Workshop's Connections UI to start it.
- Use the Scheduled management app (All / Active / Needs attention / Finished tabs) to search and inspect schedules; it is read-only — editing, pausing, deletion, and run history stay in Connections.
- Development:
pnpm install,pnpm --filter @gadgets/gatekeeper-scheduler test,pnpm --filter @gadgets/gatekeeper-scheduler build,pnpm run dev-server,pnpm run dev-client.
Troubleshooting: "Scheduled missing from navigation" → check the binding/vendor/connected account; "new schedule not listed/running" → its hook is registered disabled, enable it; "Needs attention" → callback exhausted retries, fix and re-enable; blueprint-created workspaces never inherit schedules — register again.
Related Entities
- gatekeepers
- writing a gatekeeper
- gatekeeper email — another ambient, hook-driven gatekeeper rather than an OAuth-connected external service
- gatekeepers catalog
