Cron Job Monitoring: Get Alerted When a Cron Job Stops

Published:2026-11-08

Failure alerts from cron only fire when a job runs and fails. To catch a job that never ran because the server was down, the crontab line was removed, or the job hung, use a heartbeat, also called a dead man's switch: the job checks in after each success, and something outside alerts you when a check-in is late. Services such as Healthchecks.io do this, and so does nodd heartbeat, which alerts an iPhone.

Failures that failure alerts miss

Nightly backups and reports are often set up to send an email when they fail. That setup cannot see these cases:

None of these produce a failure event, so an alert that fires on failure stays silent. You find out the backups stopped weeks ago on the day you need to restore one.

How a heartbeat (dead man's switch) works

Flip the logic. The job checks in with an outside service every time it succeeds, and the service watches for the next check-in. If it does not arrive in time, you get an alert. This is called a heartbeat or a dead man's switch.

  1. The job sends an I am alive check-in as its last step
  2. The monitor sets the next due time from an interval (say 24 hours) and a grace period (say 1 hour)
  3. If the due time passes with no check-in, it alerts. Whatever the cause, the missing check-in tells you

The monitor must run somewhere other than the job. If it lives on the same server, it goes down with the server.

Approaches without Nodd

cron's MAILTO

cron mails any output from a command to the crontab owner. MAILTO changes the recipient, and an empty value turns mail off.

MAILTO=ops@example.com
0 3 * * * /usr/local/bin/backup.sh

It needs nothing extra and you read the error output directly. But the server must be able to send mail, and it cannot see a failure with no output or a job that never ran.

Wrap the script and alert on the exit code

0 3 * * * /usr/local/bin/backup.sh || notify-failure.sh backup

Send a Slack message, an email, or a push notification when the exit code is not 0. You hear about failures right away, with the reason. Still, nothing arrives when the job never runs or hangs.

Healthchecks.io, Cronitor, and similar services

These services specialize in heartbeats. With Healthchecks.io, the job pings a URL, and you are alerted when the period plus the grace time passes. /start signals a start, /fail a failure, and an exit code appended to the URL reports the result. It supports cron expression schedules and is open source under the BSD 3-clause license, so you can host it yourself. Cronitor also uses run, complete, and fail check-ins plus a schedule to alert on missed runs and runs that take too long.

0 3 * * * /usr/local/bin/backup.sh; curl -fsS -m 10 --retry 5 https://hc-ping.com/<uuid>/$?

For run time tracking, cron schedules, and the number of integrations, these dedicated services are the most complete. If you run many jobs, look at them first.

A monitoring stack such as Prometheus

If you already run Prometheus and Grafana, export the time each job last succeeded and alert when it gets too old. Prometheus's own guidance says the key metric of a batch job is the last time it succeeded. No new tool is needed, but it assumes you operate the stack. You can forward those alerts to an iPhone with an inbound URL (see monitoring alerts on an iPhone).

Comparison

ComparedReports failures / Catches jobs that never ran / What you need
MAILTOIf there is output / No / A server that can send mail
Exit code alertRight away / No / Somewhere to send alerts
Healthchecks.io, CronitorYes, with /fail or similar / Yes, including cron schedules / An account, or your own server
Monitoring stack alertDepends on your metrics / Yes / A Prometheus-style setup
NoddYes, with nodd send / Yes, by interval and grace seconds / An iPhone and the Nodd app

Monitor with nodd heartbeat

Nodd is an iPhone app that receives notifications and questions from scripts and CI, and it can watch heartbeats. Install the CLI, run nodd login and scan the QR code with the app, or set a send key in NODD_KEY. Then run nodd heartbeat at the end of the job.

0 3 * * * /usr/local/bin/backup.sh && /usr/local/bin/nodd heartbeat nightly.backup --every 86400 --grace 3600

With &&, the check-in goes out only when the backup succeeds. A failure, a job that never runs, and a hang all show up as a missing check-in. In the app, Heartbeat monitoring in the channel details shows each name, the last check-in, and whether it is OK or Missing. See the Manual.

The example is a job that runs daily at 03:00. If its run time varies, add that variation to --grace.

Alert right away on failure

With a heartbeat alone, you learn about a failure only after the due time passes. Send an alert as soon as the exit code is not 0 to hear about it sooner.

#!/bin/sh
# /usr/local/bin/backup-job.sh
NODD=/usr/local/bin/nodd

if /usr/local/bin/backup.sh; then
  "$NODD" heartbeat nightly.backup --every 86400 --grace 3600
else
  code=$?
  "$NODD" send "Nightly backup failed" --kind alert --level high \
    --alert-key nightly.backup --field exit=$code
  exit $code
fi
0 3 * * * /usr/local/bin/backup-job.sh

An alert sent with --alert-key can be resolved once you fix the problem.

nodd resolve nightly.backup --note "Re-ran the backup by hand"

cron's PATH is often different from your interactive shell, so use the full path to nodd. nodd login saves the send key in ~/.config/nodd/config.json for the user who logged in. If the job runs from another user's crontab, log in as that user or pass NODD_KEY.

Use the API

Where you cannot install the CLI, call the API directly. interval is required, from 60 to 2,678,400 seconds. grace is 0 to 2,678,400 seconds. If omitted, it is 10% of interval and at least 60 seconds.

curl https://api.nodd.blipdrop.net/v1/heartbeats/nightly.backup \
  -H "Authorization: Bearer $NODD_KEY" \
  -H "Content-Type: application/json" \
  -d '{"interval": 86400, "grace": 3600}'

It answers 200 with name and the next due_at. When you retire a job, stop its heartbeat, or it will keep reporting the job as missing.

curl -X DELETE https://api.nodd.blipdrop.net/v1/heartbeats/nightly.backup \
  -H "Authorization: Bearer $NODD_KEY"

DELETE answers 204. You can also tap the row in the app to stop it. Managers, Owners, and Admins can do this.

Things to watch

FAQ

Are failure alerts from cron enough?
No. When the server is down, the crontab line is gone, or the job hangs, there is no failure event, so no alert fires. Add a heartbeat that checks in after each success and alerts when check-ins stop.
What is a dead man's switch for cron jobs?
It is a monitor that expects a check-in at a regular interval and alerts you when one does not arrive. For cron, the job sends the check-in as its last step.
How should I set the grace period for nodd heartbeat?
If you leave it out, it is 10% of --every. Set --grace longer to cover variation in run time and late starts.
What happens to the heartbeat when I remove a job?
The heartbeat stays and reports the job as missing. Call DELETE /v1/heartbeats/{name} or stop it from the list in the app.
Should I use Healthchecks.io or Nodd?
If you need cron expression schedules, run time tracking, or many integrations, a dedicated service such as Healthchecks.io fits better. If you want missing job alerts on an iPhone, in the same app where you answer approvals, Nodd fits.

Nodd delivers questions from scripts, CI, and AI agents to your iPhone, and returns your Face ID approval to the program that asked. There is a free plan.

Related guides