How to monitor cron jobs
Monitor cron jobs with a heartbeat, also called a dead man's switch: each run pings a unique URL when it finishes, and you are alerted when a ping does not arrive on schedule. Report the exit code and a start ping too, so failures and hung runs alert as well. Cron itself never tells you a job stopped.
What can go wrong with cron jobs
- It silently stops. The server was rebuilt, the crontab was edited, cron is not running, or the disk is full. A job that does not run produces no error anywhere.
- Works in a shell, fails in cron. Cron runs with a minimal environment (
PATH=/usr/bin:/bin, no profile). Commands that rely on your shell's PATH or variables fail only under cron. - The % sign. In a crontab line,
%means newline;date +%Fmust be writtendate +\%For the command is cut off. - Overlapping or hung runs. A run that takes longer than the interval stacks up on the next one; a hung run blocks forever.
flock -nprevents overlap but not hangs. - Errors mailed to nobody. Cron mails output to the crontab owner; on most servers that mail goes nowhere.
The signals that matter, with alert thresholds
| Signal | Alert when | Why it matters |
|---|---|---|
| Success ping | late by more than the grace period | The job did not finish successfully. |
| Exit code | non-zero | It ran and failed. |
| Run duration | over a maximum run time | Hung or much slower than usual. |
| Output of failed runs | kept with the ping | Why it failed, without SSH. |
Thresholds are starting points. Tune them after a week of data: an alert nobody acts on should be raised or removed.
How to check cron jobs by hand
crontab -l sudo crontab -l -u root ls /etc/cron.d/
systemctl status cron
grep CRON /var/log/syslog | tail -20 # or: journalctl -u cron --since today
env -i SHELL=/bin/sh PATH=/usr/bin:/bin HOME=$HOME /bin/sh -c '/usr/local/bin/my-job.sh'
How to watch cron jobs with Vigil
- In New monitor create a Heartbeat. Choose cron schedule, paste the expression and the server's timezone (e.g.
0 2 * * *in Asia/Kolkata), and a grace period longer than a normal run. - Append the ping:
0 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://puzaricloud.in/ping/<token>. With&&only successful runs ping. - Better: report every outcome.
/usr/local/bin/job.sh; curl -fsS -m 10 https://puzaricloud.in/ping/<token>/$?sends the exit code (0 = success, anything else = failure alert at once, not at the end of the grace period). - Track duration: ping
https://puzaricloud.in/ping/<token>/startbefore the job and set a maximum run time; a run that started but never finished alerts. - Keep the output:
job.sh > /tmp/job.log 2>&1; curl -fsS -m 10 --data-binary @/tmp/job.log https://puzaricloud.in/ping/<token>/$?. The body is stored with the ping and shown on the monitor.
Every alert goes to the channels you pick: email, Slack, Telegram, Discord, Microsoft Teams, Pushover, webhooks or on-call paging. Failures are confirmed by a second check before anyone is woken up.
cron jobs monitoring FAQ
What is a dead man's switch?
A check that fires when something stops happening. The job keeps "pressing the switch" by pinging; if the pings stop, the monitor alerts. It is the only way to notice a job that no longer runs at all.
What should the grace period be?
Long enough for a normal run plus a little delay, short enough that you hear about it in time. Our cron explainer suggests one for any expression, and each schedule page lists one.
What if the server cannot reach the internet?
The ping needs outbound HTTPS to puzaricloud.in. If that fails, the heartbeat goes late and alerts, which is the safe direction. Use --retry so a single network blip does not cause a false alarm.
Can one heartbeat watch several servers running the same job?
Use one heartbeat per server, so you know which one stopped; tags group them on the dashboard.