To monitor a cron job, give it a heartbeat: a unique URL that the job requests every time it finishes. A monitoring service expects that request at a regular interval. If it does not arrive in time, because the job did not run, crashed or hung, you get an alert. It takes one extra line in your crontab.
This guide shows how heartbeats work, how to add one and how to choose the right settings.
Why cron jobs need their own monitoring
Cron is reliable at starting commands and silent about what happens next. If a backup script fails at 02:00, nothing visible breaks. The website stays up and uptime checks stay green. You find out weeks later, when you need the backup and it is not there.
Typical silent failures:
- The server was down or rebooting at the scheduled time.
- The crontab was overwritten during a deployment or server migration.
- The command fails under cron because
PATHor other environment variables differ from your shell. - The script runs but hangs on a lock, a network call or a full disk.
- Credentials expired, so the job starts and exits with an error nobody reads.
Uptime monitoring cannot see any of this, because nothing public breaks. A heartbeat works the other way around: instead of the monitor checking your job, your job checks in with the monitor.
How a heartbeat works
- You create a heartbeat monitor and get a unique URL.
- You set how often the job is expected to run, for example every 24 hours, leaving some margin for slow runs.
- The job requests the URL with GET or POST when it finishes.
- If no request arrives in time, an incident opens and alerts go out.
- When the next ping arrives, the heartbeat recovers and you get a recovery notice.
Uptimecheck heartbeats work this way. Alerts go to email, Slack, Discord, Telegram, Microsoft Teams or webhooks on every plan.
Adding a heartbeat to a crontab
Suppose a backup runs every night at 02:30:
30 2 * * * /usr/local/bin/backup.sh
Add the ping after the job, chained with && so it only runs when the backup succeeds:
30 2 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://heartbeat.example.com/your-unique-id > /dev/null
What the curl options do:
-fmakes curl fail on HTTP errors instead of treating them as success.-skeeps it quiet, and-Sstill shows errors if something goes wrong.-m 10stops waiting after 10 seconds, so a slow network never blocks the job.--retry 3retries brief network problems.
Use the exact URL from your heartbeat monitor in place of the placeholder.
Ping from inside a script
For longer scripts, put the ping at the end of the script itself, after the steps that matter:
#!/usr/bin/env bash
set -euo pipefail
pg_dump northwind > /backups/northwind-$(date +%F).sql
gzip /backups/northwind-$(date +%F).sql
curl -fsS -m 10 --retry 3 https://heartbeat.example.com/your-unique-id > /dev/null
With set -e the script stops at the first failing command, so the ping is only sent when everything before it worked.
Other schedulers
Heartbeats are not limited to cron. Anything that can make an HTTP request can ping: systemd timers, Windows Task Scheduler with PowerShell’s Invoke-WebRequest, a Kubernetes CronJob, a CI pipeline or a scheduled function in your application.
Choosing the interval
The interval should match the schedule: 24 hours for a nightly job, 1 hour for an hourly job. Leave margin for normal variation in how long the job takes. If a backup usually takes 20 minutes but sometimes 50, an extra hour of margin avoids false alarms without hiding a real failure for long.
Start generous, look at how long runs actually take for a week or two, then tighten it.
Heartbeats compared with other approaches
There are other ways to watch scheduled jobs, each with gaps:
- Email from cron. Cron can email command output, but only when the job runs and produces output. If the job never starts, there is no email. Most of these emails go unread anyway.
- Log monitoring. Useful for finding errors, but a job that never ran writes no log line to search for.
- Checking results. Some teams check whether a backup file exists or a table was updated. That works, but needs custom checks for every job.
A heartbeat works for every job in the same way and catches the case the others miss: the job that did not run at all.
Long-running jobs
For jobs that take a long time, such as large backups or data migrations, consider two heartbeats: one pinged at the start and one at the end. If the start ping arrives but the end ping does not, the job hung or crashed halfway. That tells you where to look before you open a single log file.
What to give a heartbeat
Not every job needs one. Prioritise jobs whose failure you would only notice later:
- Database and file backups.
- Data imports and exports, such as product feeds or accounting syncs.
- Invoice runs, renewals and billing jobs.
- Certificate renewal jobs.
- Cleanups that keep a disk from filling up.
- Report generation that others depend on.
Give each job its own heartbeat. A shared one tells you that something did not run, but not what.
Troubleshooting a missed heartbeat
When a heartbeat alert arrives:
- Check whether cron started the job. Look in the cron or system log.
- Run the command by hand as the same user cron uses, and read the output.
- Check the environment. Use absolute paths, or set
PATHat the top of the crontab. - Check resources. A full disk or exhausted memory stops many jobs. Server monitoring shows disk, RAM and load at the time of the failure.
- Check outbound network. A firewall change can block the ping even when the job works. If the job ran but the ping failed, curl’s error appears in the job output.
Redirect job output to a log file, so there is always something to read:
30 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 && curl -fsS -m 10 https://heartbeat.example.com/your-unique-id > /dev/null
Cron job monitoring checklist
- List the scheduled jobs that matter, on every server.
- Create one heartbeat per job.
- Ping after the work succeeds, chained with
&&or at the end of aset -escript. - Set the interval to the schedule, with margin for slow runs.
- Log job output to a file.
- Send alerts to a channel someone reads, including at night for critical jobs.
- Review heartbeat history after deployments and server migrations.
Summary
Cron does not tell you when a job fails. A heartbeat does. One curl line per job turns silent failures into alerts, and the history shows you exactly when each job last ran.
Heartbeats are included on every Uptimecheck plan, together with uptime, SSL, domain, DNS and server monitoring. Try it free for 14 days, no credit card required.