Guides 5 min read

How to Monitor Cron Jobs with Heartbeats

Cron jobs fail silently. A heartbeat monitor alerts you when a scheduled job does not check in on time. How heartbeats work, how to add one to a crontab and which settings to choose.

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 PATH or 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

  1. You create a heartbeat monitor and get a unique URL.
  2. You set how often the job is expected to run, for example every 24 hours, leaving some margin for slow runs.
  3. The job requests the URL with GET or POST when it finishes.
  4. If no request arrives in time, an incident opens and alerts go out.
  5. 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:

  • -f makes curl fail on HTTP errors instead of treating them as success.
  • -s keeps it quiet, and -S still shows errors if something goes wrong.
  • -m 10 stops waiting after 10 seconds, so a slow network never blocks the job.
  • --retry 3 retries 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:

  1. Check whether cron started the job. Look in the cron or system log.
  2. Run the command by hand as the same user cron uses, and read the output.
  3. Check the environment. Use absolute paths, or set PATH at the top of the crontab.
  4. Check resources. A full disk or exhausted memory stops many jobs. Server monitoring shows disk, RAM and load at the time of the failure.
  5. 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

  1. List the scheduled jobs that matter, on every server.
  2. Create one heartbeat per job.
  3. Ping after the work succeeds, chained with && or at the end of a set -e script.
  4. Set the interval to the schedule, with margin for slow runs.
  5. Log job output to a file.
  6. Send alerts to a channel someone reads, including at night for critical jobs.
  7. 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.

Questions

What is a cron job heartbeat?

A heartbeat is a unique URL that a scheduled job requests every time it runs. The monitoring service expects that request within a set interval and alerts you if it does not arrive.

Should the ping come before or after the job?

After the work has finished successfully. Chaining the ping with && means a failed job does not ping, so you get an alert both when the job does not run and when it runs but fails.

Does a heartbeat work with systemd timers, Windows Task Scheduler or Kubernetes CronJobs?

Yes. Anything that can send an HTTP request when it finishes can ping a heartbeat, whatever schedules it.

What happens if my server is down when the job should run?

The job does not run, the ping does not arrive and you get an alert. That is one of the cases heartbeats are designed to catch.

Keep reading

Downtime is obsolete.

Set up your first monitor in under a minute and know before your customers do.

14-day free trial · No credit card required

Start free trial