A dead man's switch for your scripts
Invert the logic: instead of alerting when something fails, alert when the all-clear stops arriving.
Most alerting is built on errors: something goes wrong, something else notices, you get a message. It works until the failure is the kind where nothing is left running to notice. A dead man's switch inverts the logic — the job reports that it is alive, and silence is the alert.
What error alerting cannot see
Every one of these is silent to error-based monitoring, and all of them are ordinary:
- The machine was powered off, or the VM was terminated by a scaling policy.
- The cron entry was removed by a configuration change, or the crontab was replaced by a deployment.
- The container image failed to pull, so the job never started.
- The process was killed by the OOM killer, which does not run your error handler.
- The scheduled workflow was disabled after 60 days of repository inactivity.
- The credential expired, so the task could not log on.
- The network was down, so even the error report could not be sent.
What these have in common is that from the outside they are indistinguishable: nothing arrives. A dead man's switch turns that single shared symptom into a single alert.
How it works
You register a monitor with a schedule and a grace period, and you get a URL. The job calls the URL when it finishes successfully. If a call does not arrive within the grace period after it was due, you are alerted.
0 2 * * * /srv/app/backup.sh && curl -fsS -m 10 --retry 3 -o /dev/null https://vivere.dev/p/<your-monitor-id>
The && is doing the important work: the ping happens only if the script exits zero. Some details of that curl line matter:
-fmakes curl exit non-zero on an HTTP error rather than quietly succeeding.-sSkeeps it quiet but still prints real errors, so cron mail is not full of progress bars.-m 10caps the whole call. Without it, a monitoring request can hang and hold up the job.--retry 3survives a transient network blip, which is the main source of false alarms.-o /dev/nulldiscards the response body.
Reporting failure as well
A pure dead man's switch alerts one grace period late. Reporting the exit code alerts immediately:
0 2 * * * /srv/app/backup.sh; curl -fsS -m 10 -o /dev/null https://vivere.dev/p/<id>/$?
The semicolon rather than && is deliberate — the ping must happen whatever the exit code, because the code is the message. Zero is success; anything else raises an alert and records the number.
Pinging /start before the work begins adds duration: the monitor knows when the run began and when it ended, so you can see the night the job took four times as long before it becomes the night it did not finish.
Choosing the period and grace
The period is how often the job runs. The grace is how late a ping may be before it counts as missing, and it is the setting people get wrong.
Take the job's worst normal duration, add the largest delay the scheduler realistically adds, and add a margin. A nightly backup that usually takes ten minutes and occasionally twenty-five wants a grace of about thirty minutes, not five. A job every five minutes on a queue that sometimes backs up wants a grace of five, not one.
Too short and you are paged for a slow night, which teaches everyone to ignore the alerts. Too long and you learn about a dead job hours after it died. If you are unsure, start at roughly half the period and tighten once you have a few weeks of real timings.
Where it does not help
Be honest about the limits. A dead man's switch tells you the job ran and exited successfully. It cannot tell you the job did the right thing: a backup that ran perfectly against an empty directory pings just the same. Pair it with a cheap assertion inside the job — a row count, a file size, an archive that opens — so that "success" means something. See how to know if your backup actually ran for a worked example.
Setting one up
Vivere is a hosted dead man's switch: create a monitor, get a URL, add one line to the job, and choose where the alert lands — email, Slack, Discord, Telegram, ntfy or a webhook. The free plan covers ten monitors with no card, which is enough for most people's entire crontab.
Common questions
What is a dead man's switch in monitoring?
A check that alerts when an expected signal stops arriving, rather than when an error is reported. The job says "I am alive" on every successful run; silence past a deadline is the alert. It catches the whole class of failures where nothing is left running to report an error.
Why is a dead man's switch better than alerting on errors?
Error alerting requires something to survive the failure and send the alert. It cannot cover a machine that was off, a scheduler that was disabled, a container that never started, a process killed by the OOM killer, or a network that was down. A dead man's switch covers all of those with the same mechanism, because they all look identical from outside: silence.
How do I choose the grace period?
Take the job's normal worst-case duration, add the longest delay your scheduler realistically introduces, and add a margin. Too short and you are paged for a slow night; too long and you learn about a dead job hours late. Start at roughly half the interval and tighten once you have seen real timings.
Find out without looking
Vivere watches for the ping that does not arrive. Add one line to the job, pick where alerts should land, and you hear about the run that never happened.
Start free Read the quickstart
Ten monitors, a status page, email and webhook alerts. No card.
Last reviewed September 2026.
Related
- Cron job not running: how to find out why — A cron job stopped running and nothing told you. The five usual causes in the order worth checking, how to read the logs, and how to find out next time without looking.
- How to know if your backup actually ran — Backups fail quietly. How to verify a backup ran, why exit code zero is not proof, what to check about size and restore, and how to be told the night it does not happen.
- How to monitor a Python script that runs on a schedule — Monitoring a scheduled Python script: reporting success and failure with requests, catching exceptions with a decorator, capturing tracebacks, and alerting when a run never happens.