CronPup

← Guides

How to monitor cron jobs (and get alerted when they don't run)

Cron is a great scheduler and a terrible reporter. When a job fails, cron may email the local MAILTO address, which on most servers goes nowhere. When a job doesn't run at all (the crontab got overwritten in a deploy, the server was replaced, the container image lost its crontab, or the disk was full), nothing happens anywhere. You find out weeks later.

Three ways a cron job goes wrong

  1. It never starts. The crontab is missing, the host is down, or the schedule is wrong. No logs exist because nothing ran.
  2. It starts and fails. A non-zero exit, often with output nobody reads.
  3. It starts and hangs. It waits on a lock, a network call or a prompt, and holds up every later run.

Log-based alerting can catch case 2. It can't catch case 1, because there is no log line to alert on. Uptime monitoring can't help either: your server is up, the job just isn't happening.

The fix: invert the check (heartbeats)

Have the job report in, and treat silence as the alarm. Give each job a unique URL and request it after the job succeeds. A monitoring service knows the schedule and alerts you when the request doesn't arrive in time.

# before
0 3 * * *  /opt/jobs/backup.sh

# after
0 3 * * *  /opt/jobs/backup.sh && curl -fsS -m 10 --retry 3 https://cronpup.com/p/YOUR-UUID

The && matters: the ping only happens if the script exits 0. -m 10 stops a slow network from hanging your job, and --retry 3 rides out brief blips.

Catch failures right away, not at the next deadline

With only a success ping, a failed 3 a.m. job alerts you when the grace period runs out. To hear about it immediately, report the exit code:

0 3 * * *  /opt/jobs/backup.sh; curl -fsS -m 10 https://cronpup.com/p/YOUR-UUID/$?

A 0 counts as success, and anything else alerts immediately.

Catch hung jobs

Send a start signal first. If no finish arrives within the grace period, the job is treated as hung:

#!/bin/sh
URL=https://cronpup.com/p/YOUR-UUID
curl -fsS -m 10 "$URL/start"
/opt/jobs/backup.sh
curl -fsS -m 10 "$URL/$?"

As a bonus, you get each run's duration, which shows you when a job is slowly getting slower.

Pick the right grace period

Set the grace period a bit longer than the job's normal worst-case run time, plus clock skew. For a nightly backup that usually takes 20 minutes, 45–60 minutes is reasonable. Too tight and you'll get false alarms you learn to ignore, which is worse than no monitoring.

Use the real schedule

If the monitor knows your cron expression and timezone (e.g. 30 2 * * 1-5 in America/New_York), it expects pings exactly when cron fires, so weekends and DST changes don't cause false alarms.

CronPup does all of this. The free plan covers 10 jobs. Set up your first monitor; it takes about two minutes.