Your nightly backup job has a try/catch around the risky part and a Sentry integration for when it throws. That covers the case where the job runs and fails. It does nothing for the case where the job doesn't run at all — the server rebooted and the crontab entry never came back, the scheduler's YAML got a typo, the container image stopped building three deploys ago. No exception fires, because no code ever executed. Nothing alerts, because nothing broke in a way your monitoring knows how to see.
You find out when someone asks why last week's report never arrived, or why the database has three days of un-pruned rows. Here's the pattern that catches this class of failure, and a five-minute path to having it running today.
The dead man's switch pattern
Named after the railway brake that engages automatically if the operator stops holding it down, the pattern is a full inversion of normal monitoring. Instead of watching the job and alerting when it fails, you watch for a heartbeat and alert when it stops:
- Every scheduled task pings a URL as its last step, on success.
- A separate service tracks when it last heard from each job.
- If a job's expected interval passes with no ping, that's the alert — silence is the failure signal, not an exception.
This catches everything a try/catch can't: the cron entry that got deleted, the container that stopped scheduling, the process that hung before reaching the alerting code, the host that's down entirely.
Three ways to set this up
1. Build it yourself
Write to a timestamp column after every run, and a separate scheduled check that compares "now" against that timestamp for every job. It's a small amount of code, but it's also one more piece of infrastructure that itself needs to keep running reliably — including surviving the same kind of silent failure you're trying to detect in the first place.
2. Use a hosted service
Point your job's final step at a hosted heartbeat API and configure the expected interval in a dashboard. Fastest to start, but it's a third party sitting between "my job ran" and "I found out it didn't" — and most of these are priced per check past a small free tier, which adds up once you're monitoring more than a handful of jobs.
3. Self-host it
Same heartbeat model, but the service lives in an account you control, with no per-check billing to think about and no external party in the alert path.
The 5-minute path
We built Flatline for this — open source, self-hosted on your own Cloudflare account, alerting is a plain outbound webhook so there's no email/SMS provider to configure.
- Deploy it. Click the button on the GitHub repo — standard "Deploy to Cloudflare Workers" flow.
- Register a key on your own instance:
curl -X POST https://your-worker.your-subdomain.workers.dev/register \ -H 'Content-Type: application/json' \ -d '{"email":"you@example.com"}' - Create a check with how often the job should run and how late it's allowed to be:
curl -X POST https://your-worker.your-subdomain.workers.dev/checks \ -H 'Authorization: Bearer sk_YOUR_KEY' \ -H 'Content-Type: application/json' \ -d '{"name":"nightly-backup","period_seconds":86400,"grace_seconds":3600,"webhook_url":"https://hooks.example.com/alert"}' - Add one line to the end of the job, after it succeeds:
curl https://your-worker.your-subdomain.workers.dev/ping/CHECK_ID
That's the whole integration. Flatline sweeps every minute for checks that haven't pinged within period_seconds + grace_seconds and fires your webhook the moment one goes overdue — and again when it recovers. No API key needed to ping; the check ID itself is the credential, so the one-liner drops straight into any script, GitHub Action, or crontab without touching secrets.
What this trades away
Webhook-only alerting, not built-in email or SMS — point the webhook at whatever already pages you (Slack, PagerDuty, a custom endpoint) rather than configuring a new notification channel from scratch. And it's a heartbeat monitor, not a job scheduler or a logs product: it tells you a job didn't run, not why.
If you're already paying per-check for a hosted heartbeat monitor and mostly just need "did it ping in time, yes or no," this is worth a look — MIT-licensed, one Cloudflare Worker, your own D1 database.
Set up your first check or grab the code.