Skip to content
Back to skills

076 Api 0a2a6d49

ASecurity

```typescript export default { async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext): Promise<void> { console.log('Cron executed:', new Date(controller.scheduledTime)) }, } ```

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentjavascripttypescriptpythongojavabashexpresstestingapisecurity

Works with

  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 076-api_0a2a6d49 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 076 Api 0a2a6d49?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 076 Api 0a2a6d49
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-076-api-0a2a6d49/badge)](https://www.skillsdirectory.com/skills/tools-only-076-api-0a2a6d49)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Cron Triggers API

## Basic Handler

```typescript
export default {
  async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext): Promise<void> {
    console.log('Cron executed:', new Date(controller.scheduledTime))
  },
}
```

**JavaScript:** Same signature without types  
**Python:** `class Default(WorkerEntrypoint): async def scheduled(self, controller, env, ctx)`

## ScheduledController

```typescript
interface ScheduledController {
  scheduledTime: number // Unix ms when scheduled to run
  cron: string // Expression that triggered (e.g., "*/5 * * * *")
  type: string // Always "scheduled"
  noRetry(): void // Prevent automatic retry on failure
}
```

**Prevent retry on failure:**

```typescript
export default {
  async scheduled(controller, env, ctx) {
    try {
      await riskyOperation(env)
    } catch (error) {
      // Don't retry - failure is expected/acceptable
      controller.noRetry()
      console.error('Operation failed, not retrying:', error)
    }
  },
}
```

**When to use noRetry():**

- External API failures outside your control (avoid hammering failed services)
- Rate limit errors (retry would fail again immediately)
- Duplicate execution detected (idempotency check failed)
- Non-critical operations where skip is acceptable (analytics, caching)
- Validation errors that won't resolve on retry

## Handler Parameters

**`controller: ScheduledController`**

- Access cron expression and scheduled time

**`env: Env`**

- All bindings: KV, R2, D1, secrets, service bindings

**`ctx: ExecutionContext`**

- `ctx.waitUntil(promise)` - Extend execution for async tasks (logging, cleanup, external APIs)
- First `waitUntil` failure recorded in Cron Events

## Multiple Schedules

```typescript
export default {
  async scheduled(controller, env, ctx) {
    switch (controller.cron) {
      case '*/3 * * * *':
        ctx.waitUntil(updateRecentData(env))
        break
      case '0 * * * *':
        ctx.waitUntil(processHourlyAggregation(env))
        break
      case '0 2 * * *':
        ctx.waitUntil(performDailyMaintenance(env))
        break
      default:
        console.warn(`Unhandled: ${controller.cron}`)
    }
  },
}
```

## ctx.waitUntil Usage

```typescript
export default {
  async scheduled(controller, env, ctx) {
    const data = await fetchCriticalData() // Critical path

    // Non-blocking background tasks
    ctx.waitUntil(Promise.all([logToAnalytics(data), cleanupOldRecords(env.DB), notifyWebhook(env.WEBHOOK_URL, data)]))
  },
}
```

## Workflow Integration

```typescript
import { WorkflowEntrypoint } from 'cloudflare:workers'

export class DataProcessingWorkflow extends WorkflowEntrypoint {
  async run(event, step) {
    const data = await step.do('fetch-data', () => fetchLargeDataset())
    const processed = await step.do('process-data', () => processDataset(data))
    await step.do('store-results', () => storeResults(processed))
  }
}

export default {
  async scheduled(controller, env, ctx) {
    const instance = await env.MY_WORKFLOW.create({
      params: { scheduledTime: controller.scheduledTime, cron: controller.cron },
    })
    console.log(`Started workflow: ${instance.id}`)
  },
}
```

## Testing Handler

**Local development (/\_\_scheduled endpoint):**

```bash
# Start dev server
npx wrangler dev

# Trigger any cron
curl "http://localhost:8787/__scheduled?cron=*/5+*+*+*+*"

# Trigger specific cron with custom time
curl "http://localhost:8787/__scheduled?cron=0+2+*+*+*&scheduledTime=1704067200000"
```

**Query parameters:**

- `cron` - Required. URL-encoded cron expression (use `+` for spaces)
- `scheduledTime` - Optional. Unix timestamp in milliseconds (defaults to current time)

**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)

**Unit testing (Vitest):**

```typescript
// test/scheduled.test.ts
import { describe, it, expect } from 'vitest'
import { env } from 'cloudflare:test'
import worker from '../src/index'

describe('Scheduled Handler', () => {
  it('processes scheduled event', async () => {
    const controller = { scheduledTime: Date.now(), cron: '*/5 * * * *', type: 'scheduled' as const, noRetry: () => {} }
    const ctx = { waitUntil: (p: Promise<any>) => p, passThroughOnException: () => {} }
    await worker.scheduled(controller, env, ctx)
    expect(await env.MY_KV.get('last_run')).toBeDefined()
  })

  it('handles multiple crons', async () => {
    const ctx = { waitUntil: () => {}, passThroughOnException: () => {} }
    await worker.scheduled(
      { scheduledTime: Date.now(), cron: '*/5 * * * *', type: 'scheduled', noRetry: () => {} },
      env,
      ctx,
    )
    expect(await env.MY_KV.get('last_type')).toBe('frequent')
  })
})
```

## Error Handling

**Automatic retries:**

- Failed cron executions are retried automatically unless `noRetry()` is called
- Retry happens after a delay (typically minutes)
- Only first `waitUntil()` failure is recorded in Cron Events

**Best practices:**

```typescript
export default {
  async scheduled(controller, env, ctx) {
    try {
      await criticalOperation(env)
    } catch (error) {
      // Log error details
      console.error('Cron failed:', {
        cron: controller.cron,
        scheduledTime: controller.scheduledTime,
        error: error.message,
        stack: error.stack,
      })

      // Decide: retry or skip
      if (error.message.includes('rate limit')) {
        controller.noRetry() // Skip retry for rate limits
      }
      // Otherwise allow automatic retry
      throw error
    }
  },
}
```

## See Also

- [README.md](./README.md) - Overview
- [patterns.md](./patterns.md) - Use cases, examples
- [gotchas.md](./gotchas.md) - Common errors, testing issues

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.