Switching from UptimeRobot? Import your monitors in one click with a read-only API key.Start free →
  1. Home
  2. Monitoring
  3. Cron job monitoring

Cron job monitoring: get told when a job does not run

Every heartbeat monitor has a ping URL. The job calls it when it finishes, and if the next ping does not arrive within the period plus grace, an incident opens.

  • From $7 a month on Starter
  • Free plan: 30 monitors for HTTP(S), keyword, ping and port
  • No credit card for Free
nightly-backupExpected every 1 h · grace 5 min
on time

ping received 2 min ago

Last ping
2 min ago
Last run time
14 min
Next ping due in
58 min
Grace
5 min

Illustrative example

Try it

Check it now, in your browser

No account. Cron job monitoring: type a target and see roughly what it looks at. Nothing you type is stored.

Replace hb_YOUR_TOKEN with the token from the monitor you create. The && makes sure a failed script does not send the ping, and -fsS keeps curl quiet unless it fails.

The result appears here.

Create this monitor

What it checks

What a cron job monitor looks at

Missed ping

Set how often the job should ping and a grace period in seconds. No ping by then opens an incident.

Failure ping

Calling /fail marks the job failed immediately and stores your message or exit code as the cause.

Start ping

Calling /start records that the run began. It appears in the monitor history; the deadline is driven by finish pings.

Output attached

A POST body (or ?msg=) of up to 10 KB is stored with the ping, so the last log lines are in the incident.

Alerts

Cron job monitoring: what an alert looks like

The same event arrives as an e-mail, a Telegram message or a Slack card. This is the wording the channels send; the host, times and numbers are made up.

To [email protected]

Subject [MISSED] nightly-backup — Heartbeat missed, last ping 26 h ago

MISSED

nightly-backup

nightly-backup · Heartbeat missed, last ping 26 h ago

ErrorHeartbeat missed, last ping 26 h ago
Since14:02:11 UTC
Target/hb/hb_••••••••
Next stepThe job did not ping on time. Check the cron/task runner and its logs.

AcknowledgeOpen incident

Tenium · checked from Amsterdam · 14:02 UTC

Tenium alerts

🔴 MISSED · nightly-backup · Heartbeat missed, last ping 26 h ago

TTenium APP 2:02 PM

MISSED · nightly-backup
nightly-backup · Heartbeat missed, last ping 26 h ago

  • Error: Heartbeat missed, last ping 26 h ago
  • Target: /hb/hb_••••••••

AcknowledgeOpen incident

The job did not ping on time. Check the cron/task runner and its logs. · checked from Amsterdam

Cron job monitoring: e-mail, Discord and Google Chat work on every plan; Slack, Telegram, Teams and Mattermost start on Starter. There are no SMS or voice-call alerts.

Job duration

How long the nightly job usually takes

A heartbeat with /start and a finish ping also gives you the duration of every run, so a job that suddenly takes three times longer stands out.

Run time Threshold illustrative data
How long the nightly job usually takes. Illustrative data. 012.52537.550 Threshold 40 min 00:0006:0012:0018:0024:00 Run time (min)
A heartbeat with /start and a finish ping also gives you the duration of every run, so a job that suddenly takes three times longer stands out.
Speed

How late can a job be before you hear about it

A heartbeat has no checks to schedule. You decide the period the job should ping in and how much grace to allow; detection is the sum.

Job runs every
Grace period
You hear about a missed run after1.2 h

A missed ping is not a network measurement, so it skips multi-region confirmation and alerts as soon as the deadline passes.

Setup

How to set up cron job monitoring in 30 seconds

1

Create a heartbeat

Choose the Heartbeat type, name the job and set how often it should ping and how much grace to allow, both in seconds.

2

Copy the ping URL

Saving generates a unique URL of the form /hb/<token> on the Tenium app host. Anyone with the URL can ping it, so treat it like a secret.

3

Add one call to the job

Append a curl -fsS call to the cron line, or call the URL from the end of your script.

4

Choose alert contacts

Heartbeat misses skip multi-region confirmation, because nothing network-dependent is being tested.

Failure modes

What each error means

This is the text an incident shows in its Error line, the usual cause, and the first thing to look at.

MISSEDHeartbeat missed, last ping 26 h ago

The deadline (period plus grace) passed without a ping: the cron daemon, the server, the script or the network call is the suspect. Check the job’s own log first.

Shown as: Heartbeat missed, last ping 26 h ago

NEVERHeartbeat missed, never pinged (created 3 h ago)

The monitor was created but the first ping never arrived, usually a wrong URL or a job that was never scheduled.

Shown as: Heartbeat missed, never pinged (created 3 h ago)

/failJob reported failure (exit 2)

Your script called /fail, so the incident opens at once with your message or exit code as the cause, no waiting for the deadline.

Shown as: Job reported failure (exit 2)

LATEJob ran, ping arrived late

The run was slower than the period plus grace. If this repeats, raise the grace or fix the slow job.

Shown as: Job ran, ping arrived late

SILENTScript failed but the ping still went out

Without && (or a /fail trap) the curl runs even when the script crashed. Chain the ping after the command.

Shown as: Script failed but the ping still went out

Plans

Cron job monitoring by plan

Free
$0/mo
Starter
$7/mo
Pro
$29/mo
Agency
$59/mo
Available—✓✓✓
Monitors301003001000
Fastest interval5 min1 min30 s30 s
Regions1222
Cron heartbeats—20100500
Custom headers——✓✓
Response-time alerts——✓✓
Escalation to a second contact——✓✓
Status pages1310Unlimited

This check starts on the Starter plan. HTTP(S), keyword, ping and port checks are on every plan.

Full pricing

How lateness is calculated

A heartbeat monitor has two numbers, both in seconds: how often the job should ping, and how much grace to allow. The deadline is the time of the last finish ping plus the period plus the grace. Once the clock passes that moment, an incident opens, with a message such as "Heartbeat missed, last ping 26 hours ago". Before the very first ping, the countdown starts from the moment you created the monitor, so a brand new heartbeat that never hears from its job also alerts.

The deadline moves with each ping, not with the wall clock. A nightly backup with a period of 86400 and a grace of 3600 is late if the next ping is more than 25 hours after the previous one. That sliding behaviour has a practical consequence: choose the grace to cover your longest normal run plus start-up jitter. If the job runs at 03:00, usually finishes by 03:20 but sometimes takes 80 minutes, a grace of one hour is too tight, and a grace of two hours is safe. The checker evaluates deadlines at the monitor's own check interval, so the alert can trail the deadline by up to one interval.

The three URLs

Saving the monitor gives you a ping URL of the form https://YOUR-APP-HOST/hb/hb_TOKEN. The token is the only secret, so keep it out of public repositories. GET and POST both work, and a successful call answers "ok".

  • The bare URL, or /finish: the job succeeded. This resets the deadline and closes any open incident, which also sends a recovery notice.
  • /fail: the job failed. An incident opens immediately, without waiting for the deadline, and the cause is whatever message you sent.
  • /start: the job began. It is stored in the monitor history so you can see a run that started and never finished, but it does not move the deadline.
  • Notes: ?msg=text or ?exit=2 on a GET, or a POST body of up to 10 KB, such as the tail of the log. The incident shows it.

Curl recipes

Keep these one-liners short; the shell does the rest. Replace the URL with yours.

  • Plain cron: 0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 --retry 3 https://YOUR-APP-HOST/hb/hb_TOKEN > /dev/null. Because of &&, a failing script sends no ping and the miss alert covers it.
  • Immediate failure: backup.sh && curl -fsS $URL || curl -fsS "$URL/fail?msg=backup+failed". The second branch opens an incident right away.
  • Attach output: out=$(backup.sh 2>&1); curl -fsS --data-binary "$out" $URL/finish. Use $URL/fail in the failure branch so the log tail appears in the incident.
  • systemd: add ExecStartPost=/usr/bin/curl -fsS https://YOUR-APP-HOST/hb/hb_TOKEN to a oneshot service, so it runs only after the main command exits successfully.
  • Kubernetes CronJob or CI: put the curl as the last step of the job script; in GitHub Actions or GitLab, as the final step of a scheduled workflow.

Schedules the form cannot express

Heartbeats work with a plain period, not with a cron expression or a time zone. A job that runs only on weekdays therefore needs a period long enough to bridge the weekend, for example 3 days, which also means a Friday failure is noticed on Monday. Better: use a period of one day with two monitors, or have the job ping every day, including a "nothing to do" ping on weekends. For monthly jobs, a period of 32 days plus a day of grace does the job. The cron builder helps work out the real interval between runs of an unusual expression.

What a heartbeat catches, and what it cannot

It catches everything that stops the job from reaching its last line: a dead cron daemon, a reboot that disabled the entry, a full disk, a changed PATH, an expired password, a hung process that never exits, and a wrong edit to the crontab. It cannot know that a job which finished was also correct. A backup script that exits zero after writing a zero-byte file will happily ping. Put the ping after a verification step, for instance a file-size test or a row count, so success means something.

Heartbeats do not go through multi-region confirmation, because nothing network-dependent is being tested; the server either called in or did not. A missed ping inside an active maintenance window opens no incident, and a paused monitor keeps recording pings without alerting.

Limits and plans

Heartbeats start on the Starter plan; the Free plan has none. Allowances are 20 on Starter, 100 on Pro and 500 on Agency. Each ping URL accepts up to 30 calls a minute, and an IP gets 60 across all tokens; beyond that the endpoint answers 429, so pinging more often than once every few seconds from a busy loop is pointless. For queue workers, ping once a minute with a period of 120 and a grace of 60. The alert channels are the same as for any monitor, with escalation from Pro for the nightly job that cannot be allowed to fail; see alert escalation. The URL formats are listed in the heartbeat API docs.

Cron job monitoring questions

What if my server has no outbound internet?

The job has to make one outbound HTTPS request, so a network-isolated host cannot report in directly. Let a neighbouring machine that can reach us call the heartbeat after reading a status file from the isolated one.

Can I create heartbeats through the API?

Yes, as a monitor of type heartbeat, with a period and grace. The API documentation shows the request, and write access requires the Pro plan or above.

Is the ping URL authenticated?

The random token in the URL is the credential. If it leaks, delete the monitor and create a new one so that the old URL stops working.

Do the pings count as checks I pay for?

No. A heartbeat is one monitor against your plan total, and the number of pings you send does not change anything, apart from the rate limit.

Try cron job monitoring on Starter

This check starts on the Starter plan at $7 a month. The Free plan, no card needed, covers 30 monitors with HTTP(S), keyword, ping and port checks.