Skip to content

Commit 01fd136

Browse files
feat(skills-next): add cloudflare SDK references (#238)
1 parent 3225a72 commit 01fd136

6 files changed

Lines changed: 1822 additions & 0 deletions

File tree

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
# Crons / Job Monitoring — Sentry Cloudflare SDK
2+
3+
> Minimum SDK: `@sentry/cloudflare` v8.0.0+ (`captureCheckIn`, `withMonitor`)
4+
> Auto-instrumented `scheduled` handler: v10.x+
5+
> Status: ✅ **Generally Available**
6+
7+
---
8+
9+
## Overview
10+
11+
Sentry Crons tracks whether scheduled tasks run on time, succeed, and complete within expected durations. Sentry alerts when a job:
12+
- Misses its scheduled start time (checkin margin exceeded)
13+
- Takes too long to complete (maxRuntime exceeded)
14+
- Fails (status `"error"`)
15+
16+
Cloudflare Workers support cron triggers via the `scheduled` handler. When wrapped with `withSentry`, the scheduled handler is automatically instrumented with a `faas.cron` span that includes:
17+
- `faas.cron` — the cron expression
18+
- `faas.time` — the scheduled time (ISO 8601)
19+
- `faas.trigger``"timer"`
20+
21+
---
22+
23+
## Automatic Scheduled Handler Instrumentation
24+
25+
When you use `withSentry`, the `scheduled` handler is automatically wrapped. Errors are captured and the span records duration:
26+
27+
```typescript
28+
import * as Sentry from "@sentry/cloudflare";
29+
30+
export default Sentry.withSentry(
31+
(env: Env) => ({
32+
dsn: env.SENTRY_DSN,
33+
tracesSampleRate: 1.0,
34+
}),
35+
{
36+
async fetch(request, env, ctx) {
37+
return new Response("OK");
38+
},
39+
40+
async scheduled(controller, env, ctx) {
41+
// Automatically instrumented — errors captured, spans created
42+
await cleanupOldRecords(env.DB);
43+
},
44+
} satisfies ExportedHandler<Env>,
45+
);
46+
```
47+
48+
Configure the cron trigger in `wrangler.toml`:
49+
50+
```toml
51+
[triggers]
52+
crons = ["*/5 * * * *"] # Every 5 minutes
53+
```
54+
55+
---
56+
57+
## `Sentry.withMonitor` — Named Monitor Tracking
58+
59+
For fine-grained monitoring with named monitors (visible in the Sentry Crons dashboard):
60+
61+
```typescript
62+
async scheduled(controller, env, ctx) {
63+
ctx.waitUntil(
64+
Sentry.withMonitor("cleanup-old-records", async () => {
65+
await cleanupOldRecords(env.DB);
66+
}),
67+
);
68+
},
69+
```
70+
71+
### With Monitor Config (Upsert)
72+
73+
Supply a config to auto-create or update the monitor in Sentry:
74+
75+
```typescript
76+
const monitorConfig = {
77+
schedule: {
78+
type: "crontab",
79+
value: "*/5 * * * *",
80+
},
81+
checkinMargin: 2, // In minutes — how late is "missed"
82+
maxRuntime: 10, // In minutes — when to alert for "timed out"
83+
timezone: "America/Los_Angeles",
84+
};
85+
86+
async scheduled(controller, env, ctx) {
87+
ctx.waitUntil(
88+
Sentry.withMonitor(
89+
"cleanup-old-records",
90+
async () => {
91+
await cleanupOldRecords(env.DB);
92+
},
93+
monitorConfig,
94+
),
95+
);
96+
},
97+
```
98+
99+
---
100+
101+
## `Sentry.captureCheckIn` — Manual Check-Ins
102+
103+
For more control over the check-in lifecycle:
104+
105+
### Heartbeat (Single-Shot)
106+
107+
```typescript
108+
// Report success
109+
Sentry.captureCheckIn({ monitorSlug: "health-check", status: "ok" });
110+
111+
// Report failure
112+
Sentry.captureCheckIn({ monitorSlug: "health-check", status: "error" });
113+
```
114+
115+
### In-Progress + Completion
116+
117+
```typescript
118+
// Signal start
119+
const checkInId = Sentry.captureCheckIn({
120+
monitorSlug: "data-sync",
121+
status: "in_progress",
122+
});
123+
124+
try {
125+
await syncData(env.DB);
126+
127+
// Signal success
128+
Sentry.captureCheckIn({
129+
checkInId,
130+
monitorSlug: "data-sync",
131+
status: "ok",
132+
});
133+
} catch (error) {
134+
// Signal failure
135+
Sentry.captureCheckIn({
136+
checkInId,
137+
monitorSlug: "data-sync",
138+
status: "error",
139+
});
140+
throw error;
141+
}
142+
```
143+
144+
### With Upsert Config
145+
146+
```typescript
147+
const checkInId = Sentry.captureCheckIn(
148+
{ monitorSlug: "data-sync", status: "in_progress" },
149+
{
150+
schedule: { type: "crontab", value: "0 * * * *" },
151+
checkinMargin: 5,
152+
maxRuntime: 30,
153+
timezone: "UTC",
154+
},
155+
);
156+
```
157+
158+
---
159+
160+
## Schedule Types
161+
162+
| Type | Format | Example |
163+
|------|--------|---------|
164+
| `crontab` | Standard cron expression | `"*/5 * * * *"` (every 5 min) |
165+
| `interval` | Repeated interval | `{ value: 10, unit: "minute" }` |
166+
167+
### Interval Schedule
168+
169+
```typescript
170+
const monitorConfig = {
171+
schedule: {
172+
type: "interval",
173+
value: 10,
174+
unit: "minute", // "minute", "hour", "day", "week", "month", "year"
175+
},
176+
checkinMargin: 2,
177+
maxRuntime: 10,
178+
};
179+
```
180+
181+
---
182+
183+
## Monitor Config Options
184+
185+
| Option | Type | Default | Notes |
186+
|--------|------|---------|-------|
187+
| `schedule.type` | `"crontab" \| "interval"` || Required |
188+
| `schedule.value` | `string \| number` || Cron expression or interval value |
189+
| `schedule.unit` | `string` || Required for `interval` type |
190+
| `checkinMargin` | `number` || Minutes before a check-in is considered missed |
191+
| `maxRuntime` | `number` || Minutes before a running job is considered timed out |
192+
| `timezone` | `string` | `"UTC"` | IANA timezone for crontab schedules |
193+
| `failureIssueThreshold` | `number` || Number of consecutive failures before creating an issue |
194+
| `recoveryThreshold` | `number` || Number of consecutive successes before resolving an issue |
195+
196+
---
197+
198+
## Best Practices
199+
200+
1. **Use `withMonitor` for most cases** — it handles the check-in lifecycle automatically and records duration.
201+
202+
2. **Use `ctx.waitUntil`** — wrap `withMonitor` in `ctx.waitUntil()` to ensure the check-in is flushed before the worker terminates.
203+
204+
3. **Use upsert configs** — supply `monitorConfig` to auto-create monitors. This avoids manual configuration in the Sentry UI.
205+
206+
4. **Name monitors clearly** — use descriptive slugs like `"daily-cleanup"` or `"hourly-sync"`, not `"cron-1"`.
207+
208+
5. **Set reasonable thresholds**`checkinMargin` should be slightly larger than typical scheduling jitter. `maxRuntime` should be longer than the 99th percentile duration.
209+
210+
---
211+
212+
## Troubleshooting
213+
214+
| Issue | Solution |
215+
|-------|----------|
216+
| Monitor not appearing in Crons dashboard | Ensure `captureCheckIn` or `withMonitor` is called at least once with a valid `monitorSlug` |
217+
| Check-in always shows "missed" | Verify `checkinMargin` is large enough for scheduling jitter |
218+
| Check-in shows "timed out" | Verify `maxRuntime` exceeds expected job duration |
219+
| In-progress check-in never completes | Ensure both `in_progress` and `ok`/`error` check-ins use the same `checkInId` |
220+
| Schedule mismatch | Ensure `schedule.value` in config matches the actual cron expression in `wrangler.toml` |

0 commit comments

Comments
 (0)