Monitor Cloudflare Workers Cron Triggers — detect failed scheduled runs
A Cloudflare Cron Trigger invokes your Worker's scheduled() handler on a cron
schedule. If that handler throws — an unhandled exception, a failed subrequest, a timeout —
Cloudflare marks the invocation as errored in Workers Analytics, but sends you nothing. If the
trigger silently stops firing, you also get nothing. Add one fetch ping inside the
handler and LastPing catches every failure and every missed run in seconds.
Setup: one fetch in your scheduled() handler
Ping on success, ping /fail in the catch block. Works from any Worker runtime.
Create a heartbeat monitor in LastPing
In the console, create a monitor with the same cron schedule as your trigger. Cloudflare crons run in UTC, so set the monitor's timezone to UTC. Copy the ping URL.
Declare the cron in wrangler.toml
Set your schedule and add the monitor id as a Worker variable (or a secret via wrangler secret put):
Ping from the scheduled() handler
Ping on success; fetch the /fail path on error, then re-throw so the invocation still shows as errored in Cloudflare too:
Use waitUntil for the ping if you return early
If your handler returns before the ping resolves, wrap it in ctx.waitUntil(fetch(ping)) so the runtime keeps the request alive until the ping completes.
What this catches
- Handler throws — the success ping is skipped (or the /fail ping fires); silence in the grace window opens an incident.
- Trigger stops firing — a disabled or removed Cron Trigger produces no ping → incident opens.
- Silent no-op — validate the work actually happened and only ping on confirmed success.
- Recovery — the next successful invocation closes the incident automatically.
Also on Fly.io? See Fly.io scheduled machines. On Render? See Render cron jobs. For the general pattern, see Monitor cron jobs, and Node.js scripts for the runtime details.
Questions people ask
Front-loaded answers — the most important fact first.
-
Does Cloudflare alert when a Cron Trigger fails?
No. A throwing
scheduled()handler is recorded as an errored invocation in Workers Analytics and the dashboard, but no notification is sent. If the trigger stops firing entirely, nothing alerts you. A dead-man's-switch ping catches both — it expects a check-in on every run and opens an incident when one doesn't arrive. -
What timezone do Cloudflare Cron Triggers use?
Always UTC. There is no per-Worker timezone setting, so write your cron expression in UTC and set the LastPing monitor to UTC as well.
-
Will the ping count against my subrequest limit?
The ping is a single outbound
fetch, which counts as one subrequest — negligible against the per-invocation limit. Usectx.waitUntil()if the handler might return before the ping resolves. -
Is this free?
Yes. LastPing is free and fully hosted with no monitor cap and no paid tier. See vs Healthchecks.io and vs Cronitor.
A Worker cron that throws tells no one. One fetch changes that.
Ping from your scheduled() handler. First alert in under a minute — and LastPing monitors itself the same way.