Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/cron-triggers/api.md
1# Cron Triggers API23## Basic Handler45```typescript6export default {7async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext): Promise<void> {8console.log("Cron executed:", new Date(controller.scheduledTime));9},10};11```1213**JavaScript:** Same signature without types14**Python:** `class Default(WorkerEntrypoint): async def scheduled(self, controller, env, ctx)`1516## ScheduledController1718```typescript19interface ScheduledController {20scheduledTime: number; // Unix ms when scheduled to run21cron: string; // Expression that triggered (e.g., "*/5 * * * *")22type: string; // Always "scheduled"23noRetry(): void; // Prevent automatic retry on failure24}25```2627**Prevent retry on failure:**28```typescript29export default {30async scheduled(controller, env, ctx) {31try {32await riskyOperation(env);33} catch (error) {34// Don't retry - failure is expected/acceptable35controller.noRetry();36console.error("Operation failed, not retrying:", error);37}38},39};40```4142**When to use noRetry():**43- External API failures outside your control (avoid hammering failed services)44- Rate limit errors (retry would fail again immediately)45- Duplicate execution detected (idempotency check failed)46- Non-critical operations where skip is acceptable (analytics, caching)47- Validation errors that won't resolve on retry4849## Handler Parameters5051**`controller: ScheduledController`**52- Access cron expression and scheduled time5354**`env: Env`**55- All bindings: KV, R2, D1, secrets, service bindings5657**`ctx: ExecutionContext`**58- `ctx.waitUntil(promise)` - Extend execution for async tasks (logging, cleanup, external APIs)59- First `waitUntil` failure recorded in Cron Events6061## Multiple Schedules6263```typescript64export default {65async scheduled(controller, env, ctx) {66switch (controller.cron) {67case "*/3 * * * *": ctx.waitUntil(updateRecentData(env)); break;68case "0 * * * *": ctx.waitUntil(processHourlyAggregation(env)); break;69case "0 2 * * *": ctx.waitUntil(performDailyMaintenance(env)); break;70default: console.warn(`Unhandled: ${controller.cron}`);71}72},73};74```7576## ctx.waitUntil Usage7778```typescript79export default {80async scheduled(controller, env, ctx) {81const data = await fetchCriticalData(); // Critical path8283// Non-blocking background tasks84ctx.waitUntil(Promise.all([85logToAnalytics(data),86cleanupOldRecords(env.DB),87notifyWebhook(env.WEBHOOK_URL, data),88]));89},90};91```9293## Workflow Integration9495```typescript96import { WorkflowEntrypoint } from "cloudflare:workers";9798export class DataProcessingWorkflow extends WorkflowEntrypoint {99async run(event, step) {100const data = await step.do("fetch-data", () => fetchLargeDataset());101const processed = await step.do("process-data", () => processDataset(data));102await step.do("store-results", () => storeResults(processed));103}104}105106export default {107async scheduled(controller, env, ctx) {108const instance = await env.MY_WORKFLOW.create({109params: { scheduledTime: controller.scheduledTime, cron: controller.cron },110});111console.log(`Started workflow: ${instance.id}`);112},113};114```115116## Testing Handler117118**Local development (/__scheduled endpoint):**119```bash120# Start dev server121npx wrangler dev122123# Trigger any cron124curl "http://localhost:8787/__scheduled?cron=*/5+*+*+*+*"125126# Trigger specific cron with custom time127curl "http://localhost:8787/__scheduled?cron=0+2+*+*+*&scheduledTime=1704067200000"128```129130**Query parameters:**131- `cron` - Required. URL-encoded cron expression (use `+` for spaces)132- `scheduledTime` - Optional. Unix timestamp in milliseconds (defaults to current time)133134**Production security:** The `/__scheduled` endpoint is available in production and can be triggered by anyone. Block it or implement authentication - see [gotchas.md](./gotchas.md#security-concerns)135136**Unit testing (Vitest):**137```typescript138// test/scheduled.test.ts139import { describe, it, expect } from "vitest";140import { env } from "cloudflare:test";141import worker from "../src/index";142143describe("Scheduled Handler", () => {144it("processes scheduled event", async () => {145const controller = { scheduledTime: Date.now(), cron: "*/5 * * * *", type: "scheduled" as const, noRetry: () => {} };146const ctx = { waitUntil: (p: Promise<any>) => p, passThroughOnException: () => {} };147await worker.scheduled(controller, env, ctx);148expect(await env.MY_KV.get("last_run")).toBeDefined();149});150151it("handles multiple crons", async () => {152const ctx = { waitUntil: () => {}, passThroughOnException: () => {} };153await worker.scheduled({ scheduledTime: Date.now(), cron: "*/5 * * * *", type: "scheduled", noRetry: () => {} }, env, ctx);154expect(await env.MY_KV.get("last_type")).toBe("frequent");155});156});157```158159## Error Handling160161**Automatic retries:**162- Failed cron executions are retried automatically unless `noRetry()` is called163- Retry happens after a delay (typically minutes)164- Only first `waitUntil()` failure is recorded in Cron Events165166**Best practices:**167```typescript168export default {169async scheduled(controller, env, ctx) {170try {171await criticalOperation(env);172} catch (error) {173// Log error details174console.error("Cron failed:", {175cron: controller.cron,176scheduledTime: controller.scheduledTime,177error: error.message,178stack: error.stack,179});180181// Decide: retry or skip182if (error.message.includes("rate limit")) {183controller.noRetry(); // Skip retry for rate limits184}185// Otherwise allow automatic retry186throw error;187}188},189};190```191192## See Also193194- [README.md](./README.md) - Overview195- [patterns.md](./patterns.md) - Use cases, examples196- [gotchas.md](./gotchas.md) - Common errors, testing issues197