Back to skills
SKILL.md
327 Patterns B807ff7a
ASecurity```typescript export default { async scheduled(controller, env, ctx) { const response = await fetch('https://api.example.com/data', { headers: { Authorization: `Bearer ${env.API_KEY}` }, }) if (!response.ok) throw new Error(`API error: ${response.status}`) ctx.waitUntil(env.MY_KV.put('cached_data', JSON.stringify(await response.json()), { expirationTtl: 3600 })) }, } ```
- 9 stars
- 0 votes
- 0 copies
- 0 views
- Added October 11, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add tools-only/X-Skills --skill 327-patterns_b807ff7a --agent claude-codeAre you the author of 327 Patterns B807ff7a?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-327-patterns-b807ff7a)# Cron Triggers Patterns
## API Data Sync
```typescript
export default {
async scheduled(controller, env, ctx) {
const response = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${env.API_KEY}` },
})
if (!response.ok) throw new Error(`API error: ${response.status}`)
ctx.waitUntil(env.MY_KV.put('cached_data', JSON.stringify(await response.json()), { expirationTtl: 3600 }))
},
}
```
## Database Cleanup
```typescript
export default {
async scheduled(controller, env, ctx) {
const result = await env.DB.prepare(`DELETE FROM sessions WHERE expires_at < datetime('now')`).run()
console.log(`Deleted ${result.meta.changes} expired sessions`)
ctx.waitUntil(env.DB.prepare('VACUUM').run())
},
}
```
## Report Generation
```typescript
export default {
async scheduled(controller, env, ctx) {
const startOfWeek = new Date()
startOfWeek.setDate(startOfWeek.getDate() - 7)
const { results } = await env.DB.prepare(
`SELECT date, revenue, orders FROM daily_stats WHERE date >= ? ORDER BY date`,
)
.bind(startOfWeek.toISOString())
.all()
const report = {
period: 'weekly',
totalRevenue: results.reduce((sum, d) => sum + d.revenue, 0),
totalOrders: results.reduce((sum, d) => sum + d.orders, 0),
dailyBreakdown: results,
}
const reportKey = `reports/weekly-${Date.now()}.json`
await env.REPORTS_BUCKET.put(reportKey, JSON.stringify(report))
ctx.waitUntil(
env.SEND_EMAIL.fetch('https://example.com/send', {
method: 'POST',
body: JSON.stringify({
to: 'team@example.com',
subject: 'Weekly Report',
reportUrl: `https://reports.example.com/${reportKey}`,
}),
}),
)
},
}
```
## Health Checks
```typescript
export default {
async scheduled(controller, env, ctx) {
const services = [
{ name: 'API', url: 'https://api.example.com/health' },
{ name: 'CDN', url: 'https://cdn.example.com/health' },
]
const checks = await Promise.all(
services.map(async (service) => {
const start = Date.now()
try {
const response = await fetch(service.url, { signal: AbortSignal.timeout(5000) })
return { name: service.name, status: response.ok ? 'up' : 'down', responseTime: Date.now() - start }
} catch (error) {
return { name: service.name, status: 'down', responseTime: Date.now() - start, error: error.message }
}
}),
)
ctx.waitUntil(env.STATUS_KV.put('health_status', JSON.stringify(checks)))
const failures = checks.filter((c) => c.status === 'down')
if (failures.length > 0)
ctx.waitUntil(
fetch(env.ALERT_WEBHOOK, {
method: 'POST',
body: JSON.stringify({
text: `${failures.length} service(s) down: ${failures.map((f) => f.name).join(', ')}`,
}),
}),
)
},
}
```
## Batch Processing (Rate-Limited)
```typescript
export default {
async scheduled(controller, env, ctx) {
const queueData = await env.QUEUE_KV.get('pending_items', 'json')
if (!queueData || queueData.length === 0) return
const batch = queueData.slice(0, 100)
const results = await Promise.allSettled(
batch.map((item) =>
fetch('https://api.example.com/process', {
method: 'POST',
headers: { Authorization: `Bearer ${env.API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(item),
}),
),
)
console.log(`Processed ${results.filter((r) => r.status === 'fulfilled').length}/${batch.length} items`)
ctx.waitUntil(env.QUEUE_KV.put('pending_items', JSON.stringify(queueData.slice(100))))
},
}
```
## Queue Integration
```typescript
export default {
async scheduled(controller, env, ctx) {
const batch = await env.MY_QUEUE.receive({ batchSize: 100 })
const results = await Promise.allSettled(
batch.messages.map(async (msg) => {
await processMessage(msg.body, env)
await msg.ack()
}),
)
console.log(`Processed ${results.filter((r) => r.status === 'fulfilled').length}/${batch.messages.length}`)
},
}
```
## Monitoring & Observability
```typescript
export default {
async scheduled(controller, env, ctx) {
const startTime = Date.now()
const meta = { cron: controller.cron, scheduledTime: controller.scheduledTime }
console.log('[START]', meta)
try {
const result = await performTask(env)
console.log('[SUCCESS]', { ...meta, duration: Date.now() - startTime, count: result.count })
ctx.waitUntil(
env.METRICS.put(`cron:${controller.scheduledTime}`, JSON.stringify({ ...meta, status: 'success' }), {
expirationTtl: 2592000,
}),
)
} catch (error) {
console.error('[ERROR]', { ...meta, duration: Date.now() - startTime, error: error.message })
ctx.waitUntil(
fetch(env.ALERT_WEBHOOK, {
method: 'POST',
body: JSON.stringify({ text: `Cron failed: ${controller.cron}`, error: error.message }),
}),
)
throw error
}
},
}
```
**View logs:** `npx wrangler tail` or Dashboard → Workers & Pages → Worker → Logs
## Durable Objects Coordination
```typescript
export default {
async scheduled(controller, env, ctx) {
const stub = env.COORDINATOR.get(env.COORDINATOR.idFromName('cron-lock'))
const acquired = await stub.tryAcquireLock(controller.scheduledTime)
if (!acquired) {
controller.noRetry()
return
}
try {
await performTask(env)
} finally {
await stub.releaseLock()
}
},
}
```
## Python Handler
```python
from workers import WorkerEntrypoint
class Default(WorkerEntrypoint):
async def scheduled(self, controller, env, ctx):
data = await env.MY_KV.get("key")
ctx.waitUntil(env.DB.execute("DELETE FROM logs WHERE created_at < datetime('now', '-7 days')"))
```
## Testing Patterns
**Local testing with /\_\_scheduled:**
```bash
# Start dev server
npx wrangler dev
# Test specific cron
curl "http://localhost:8787/__scheduled?cron=*/5+*+*+*+*"
# Test with specific time
curl "http://localhost:8787/__scheduled?cron=0+2+*+*+*&scheduledTime=1704067200000"
```
**Unit tests:**
```typescript
// test/scheduled.test.ts
import { describe, it, expect, vi } from 'vitest'
import { env } from 'cloudflare:test'
import worker from '../src/index'
describe('Scheduled Handler', () => {
it('executes cron', async () => {
const controller = { scheduledTime: Date.now(), cron: '*/5 * * * *', type: 'scheduled' as const, noRetry: vi.fn() }
const ctx = { waitUntil: vi.fn(), passThroughOnException: vi.fn() }
await worker.scheduled(controller, env, ctx)
expect(await env.MY_KV.get('last_run')).toBeDefined()
})
it('calls noRetry on duplicate', async () => {
const controller = { scheduledTime: 1704067200000, cron: '0 2 * * *', type: 'scheduled' as const, noRetry: vi.fn() }
await env.EXECUTIONS.put('0 2 * * *-1704067200000', '1')
await worker.scheduled(controller, env, { waitUntil: vi.fn(), passThroughOnException: vi.fn() })
expect(controller.noRetry).toHaveBeenCalled()
})
})
```
## See Also
- [README.md](./README.md) - Overview
- [api.md](./api.md) - Handler implementation
- [gotchas.md](./gotchas.md) - Troubleshooting
Files in this skill
- README.md
- skill.md
Attribution
Comments
Loading comments…