Guide
How to know when a cron job or backup stops running
A job that fails loudly gets noticed. A job that stops running doesn't: no error, no email, nothing in the logs, until the day you need last night's backup. The usual answer is a heartbeat.
Why a stopped job is silent
Cron runs what's in the crontab, on a machine that's up. If the server was replaced, the crontab edited, the disk filled or the script stuck waiting for a lock, nothing runs and nothing complains. Cron's own email (MAILTO) only tells you about a job that ran and printed something.
A heartbeat: an alert on silence
A heartbeat turns it around. The job pings an address each time it finishes, and something else expects that ping and alerts you when it doesn't come on time. It's also called a dead man's switch. It catches every way a job can stop, because it doesn't need to know why.
You can build the other end yourself: an address that notes the time of the last ping, and a check on another machine that alerts when that time is too old. Then that check needs watching too, which is why most people use a service for it.
The one line
Put the ping after the job, joined with &&, so it's sent only when the job succeeds:
0 3 * * * /usr/local/bin/backup.sh && curl -fsS --retry 3 https://hb.badgerbell.com/<your id> > /dev/null
-fmakes curl fail on an error answer,-sSkeeps it quiet unless something goes wrong, and--retry 3tries again after a network blip.- The job's exit code decides. A backup script that hides its own errors and exits with 0 still pings, so make it exit with an error when it fails.
To hear about a failure at once, rather than when the ping is late, ping /fail when the job fails. The message after m= goes into the alert:
if /usr/local/bin/backup.sh; then curl -fsS --retry 3 https://hb.badgerbell.com/<your id> > /dev/null else curl -fsS --retry 3 "https://hb.badgerbell.com/<your id>/fail?m=backup+failed" > /dev/null fi
The grace period
The grace period is how late a ping can be and still count as on time. Make it longer than the job's slowest run, plus any wait before it starts. A nightly backup that usually takes 10 minutes and sometimes 40 needs more than 40 minutes' grace, or it alerts on its slow nights.
Time zones
BadgerBell's heartbeat doesn't read your crontab. It expects a ping once every period, counted from the last one: "every 1 day", "every 1 hour". So the server's time zone doesn't matter. One thing does: when the server's clock follows daylight saving, a job at 03:00 runs 23 or 25 hours apart twice a year. A grace period of more than an hour covers it.
With BadgerBell
- Each heartbeat has its own address at hb.badgerbell.com, with
/failand/startbeside it. Pings are GET requests, as curl sends them. A HEAD request (curl -I) doesn't count. - Set the period and the grace, or start from Nightly (every day, 30 minutes' grace), Hourly (10 minutes) or Weekly (1 hour).
- No ping within the period and the grace, or a ping to
/fail, and the heartbeat goes down and you're alerted. The next good ping brings it back up. - A heartbeat counts as 1 monitor, however often the job runs. It's on every plan, Free included.
Set it up with your assistant
Connect BadgerBell, paste one prompt, and your assistant proposes your monitors.
claude mcp add --transport http badgerbell https://app.badgerbell.com/mcp
Anything public or destructive waits for you in BadgerBell.