Skip to content
Get started

How to monitor Linux cron jobs for missed runs

Native cron only emails you when a job produces output — it is blind to a job that never runs at all because the daemon is down, the machine is off, or the crontab is missing. To catch missed runs, use heartbeat monitoring: the job pings an external URL on success, and you get alerted when the expected ping doesn't arrive within a grace period. MAILTO catches errors; a dead man's switch catches the silences.

What does native cron actually tell you?

cron(8) sends mail to the crontab owner whenever a job produces output. If a job writes nothing to stdout or stderr, no email is sent. If the job never runs at all — because the cron daemon stopped, the server was rebooted, or the crontab entry was removed — cron sends nothing, because there is no output to mail.

  • MAILTO works: set MAILTO in your crontab to route job output to a real inbox. But a job that produces no output on failure still sends nothing.
  • The silent-miss gap: a job that never ran produces no log, no email, no trace. This is the case most worth monitoring.
  • MAILTO="" disables all mail — make sure you haven't silenced yourself with an empty MAILTO.

How do I detect a missed run?

Use a dead man's switch: append a ping to the crontab line with && so it fires only on a successful exit. A monitor waits for that ping and alerts you when it doesn't arrive:

crontab -e
# && ensures the ping fires only on exit 0. A failure or missed run sends no ping.
*/5 * * * * /path/to/job.sh && curl -fsS -m 10 --retry 3 "https://ping.cronshield.com/<your-check-id>"

Set the monitor's grace time above the expected job duration. If no ping arrives within the period plus grace, you get an alert. This catches four failure modes native cron misses entirely:

  • The whole machine goes down
  • The cron daemon is not running or has an invalid configuration
  • The job exits with a non-zero exit code (producing no output)
  • The job runs abnormally long — longer than its interval

How do I confirm the cron daemon and crontab are healthy?

systemctl status cron 2>/dev/null || systemctl status crond   # daemon running?
crontab -l          # current user's entries
grep -R "job.sh" /etc/cron* /var/spool/cron/   # system-level entries
PING_URL is a placeholder for the check-specific endpoint you get when you create a monitor. The CronShield receiver ships in an upcoming release; the heartbeat pattern is what matters today.

Add a missed-run alert to this job

The free tier gives you a heartbeat endpoint and an email alert when an expected ping doesn't arrive. Paid tiers add the log-aware diagnosis — the last log line and a likely cause in the alert. The heartbeat receiver ships in an upcoming release; see the plans to learn what each tier adds.

Frequently asked questions

Why doesn't MAILTO tell me when my cron job didn't run?
MAILTO routes whatever output the job produces to an email address. A job that never runs produces no output, so there is nothing to mail. MAILTO covers the job-ran-and-errored case; a heartbeat monitor covers the job-never-ran case.
What is the -s flag on cron?
The cron -s option sends job output to the system log via syslog instead of email — useful when no mail transfer agent is installed. It does not add missed-run detection; you still need a heartbeat for that.