Cron job monitoring: a missing ping catches the failures cron hides
Cron says nothing when a job fails or never starts. A heartbeat ping fixes that: here are the setup steps, the grace-time setting that matters most, and the shell habits that make a monitor lie.
Nihar Rout · · Updated · 10 min read · 16 views
Cron job monitoring means your job reports in, instead of you checking on it. The job pings a unique URL when it finishes, and an outside service raises an alarm when the ping doesn't arrive on time. That catches the failures cron itself never mentions: a dead machine, a stopped daemon, a non-zero exit, a job that runs too long. We read the docs on October 25, 2026.
Cron job monitoring works by waiting for a ping, not by watching the job
Cron runs a command at a time you set and, by default, says nothing about how it went. The usual fix is email: cron mails a crontab's job output to the address in MAILTO. The Healthchecks.io cron guide lists the weaknesses of that approach in its own words: "For MAILTO to work, the server needs to have a configured MTA," and "You will not be notified if the whole machine is powered off or has lost network connection." A job that prints output sends an email on every run, which the same page says can cause alert fatigue.
Heartbeat monitoring, which the Healthchecks.io page also calls a dead man's switch, reverses the direction. The monitor is the one that waits. If the expected request doesn't arrive at the expected time, it notifies you. Because the alarm depends on something not happening, it fires even when the machine that should have sent the signal is gone.
The Healthchecks.io page names four failures this catches:
- The whole machine goes down.
- The cron daemon is not running or has an invalid configuration.
- Cron starts the task, but it exits with a non-zero exit code.
- The cron job runs for an abnormally long time.
Notice what the list has in common. In most of these cases no output is ever produced, so there is nothing for MAILTO to carry. That is the case for putting the check outside the machine.
How to add a heartbeat to a crontab line, step by step
The setup is the same in any heartbeat tool. We use Healthchecks.io's documented commands because, in our view, its docs describe the pattern most clearly, but the steps carry over.
- Create a check for the job and match its schedule. Healthchecks.io accepts either a simple repeating period or the same cron expression you have in your crontab.
- Copy the ping URL the service gives the check. It is unique to that job, so treat it like a low-grade secret: anyone who has it can make the job look healthy.
- Append the ping to the command, joined with two ampersands, so it runs only if the job succeeds. The documented form is: /home/me/backup.sh && curl -fsS -m 10 --retry 5 -o /dev/null https://hc-ping.com/your-uuid-here
- Set the grace time (next section).
- Run the job once by hand and confirm the check turns green.
- Break it on purpose. Change the script to exit with an error, or comment out the ping, and wait for the alert. A monitor you have never seen fire is a monitor you haven't tested.
The page says the curl line can also go as the last line of the script instead. The two ampersands mean curl runs only if the script exits with code 0. The curl options each do one job, per the same page: -f treats non-200 responses as errors, -s silences output, -S re-enables error messages, -m sets a maximum total time, --retry retries transient errors, and -o /dev/null discards stdout.
Grace time is the setting that decides your false alarms
Every heartbeat check has two timing numbers. In the Healthchecks.io check configuration docs, "Period is the expected time between pings" and "Grace Time is the additional time to wait before sending an alert when a check is late." The alert fires only after the period and the grace time have both run out.
Set it too short and a slow night produces a false alarm. Set it too long and a real failure sits unnoticed. The Healthchecks.io cron guide says: "Set Grace Time to be above the expected duration of your cron job." Its worked example uses a 30-minute grace time for a job that takes 15 to 25 minutes.
In our view, the right way to pick the number is to look at the slowest run you can remember, add a margin, and choose the failure you would rather live with. A nightly backup that must finish before morning can carry hours of grace. A job that feeds a dashboard people read at nine should not.
Why your pings arrive an hour early or late
Cron expressions are interpreted in a time zone, and the monitor has to agree with your server. The Healthchecks.io cron guide says that if a job consistently pings an hour early or late, "the likely cause is a timezone mismatch" between the machine and the service's configuration. Its suggested check on GNU/Linux is to run timedatectl status and read the "Time zone" line. The check configuration page also tells you to set the time zone when the machine doesn't use UTC.
Start, fail and exit-status pings tell the monitor more than success alone
A bare success ping only proves the job finished. Two extra signals, documented on the Healthchecks.io ping API page, make the monitor much more useful.
| Ping | URL form | What it adds |
|---|---|---|
| Success | hc-ping.com/your-uuid | Job finished |
| Start | hc-ping.com/your-uuid/start | Run time, and overrun detection |
| Fail | hc-ping.com/your-uuid/fail | An alert right away |
| Exit status | hc-ping.com/your-uuid/ followed by 0 to 255 | Success on 0, failure on anything else |
| Log | hc-ping.com/your-uuid/log | An event in the history; the status stays the same |
The API page says "Sending a 'start' signal is optional, but it enables a few extra features": measuring execution time and detecting overruns past the grace time. The check configuration page explains the overrun rule: after a start signal the service expects a success signal within the grace time, and if it doesn't arrive it marks the check as failed and sends alerts.
For failures, the API page says "Actively signaling a failure minimizes the delay from your monitored service failing to you receiving an alert." Without it you wait for the whole period plus grace to pass. And it states that Healthchecks.io "interprets 0 as a success and all other values as a failure."
One detail for jobs that overlap or run in parallel: every endpoint takes an optional rid parameter, a client-picked UUID, which the service uses to match the right start ping to its finish and calculate an accurate duration. The API page does not describe how overlapping runs are otherwise treated, so we make no claim about that.
Four shell habits that make a heartbeat lie
None of these appear as warnings in the vendor docs. They are our reading of how the documented pattern behaves, so test your own version.
- The job swallows its own errors. The two-ampersand form trusts the script's exit code. If a script runs ten steps, one fails, and the last command succeeds, the exit code is 0 and the ping goes out. Make the script stop at the first error, or ping from the end only after you check the result yourself.
- A pipeline hides the failure. In a shell, a pipeline's exit status normally comes from its last command. A dump that fails but is piped into a compressor can look like success.
- The ping goes first. If the ping sits at the top of the script, it proves the job started, not that it worked. Use a start ping at the top and a success ping at the bottom.
- The monitor is unreachable. A network blip during the ping looks like a failed job. That is why the documented command carries -m 10 and --retry 5. Keep the same care for a start ping: a failed request to the monitor shouldn't stop the job itself from running.
Appending the job's exit code to the ping URL, which the table above documents, is in our view the tidiest way to cover both success and failure with one line.
Which cron job monitoring tool to use
Upfynd lists 144 products in Testing & Monitoring and 211 in Open Source as of October 25, 2026. Three of them cover scheduled jobs directly, and one common uptime tool does not appear to.
| Tool | How it detects a problem | Free plan, per its pricing page |
|---|---|---|
| Healthchecks.io | Waits for a ping inside period plus grace time | Hobbyist: 20 checks |
| Cronitor | Monitors send run, complete and fail events | Hacker: 5 monitors |
| Sentry | Check-ins reported as missed (including timeouts), failed or successful | Needs an existing Sentry account |
Healthchecks.io. Its pricing page lists the Hobbyist plan at $0 a month for 20 checks, Supporter at $5 for 20, Business at $20 for 100 and Business Plus at $80 for 1,000. The page uses a dollar sign but never names the currency, so read those as dollars with that caveat. Its self-hosting page says "Healthchecks is open-source, and is licensed under the BSD 3-clause license" and lists Python 3.12+, Django 6.0 and PostgreSQL or MySQL as the building blocks. That makes it the pick if you want the whole monitor on your own server. In our view, it is also the easiest one to learn from, because its docs spell out the ping protocol.
Cronitor. Cronitor's pricing page lists a free Hacker plan at $0 with 5 monitors, a Business plan at $2 a month per monitor plus $5 a month per user, and Enterprise from $6,000 a year. It shows a dollar sign without naming the currency. Because Business is billed per monitor, the cost grows with the number of jobs you watch. If you watch 40 scheduled tasks, check the arithmetic before you commit.
Sentry. Sentry's job monitoring docs define a check-in as missed when "The job didn't execute in the predicted timeframe or frequency," and a timeout as "a timeout failure event when a job sent an initial check-in but failed to send a final check-in." The crons overview says you need an existing Sentry account and project. We read no plan or pricing information on the pages we opened, so check Sentry's own pricing before you count on cron monitoring being free. If you already use Sentry for errors, the appeal is having job failures in the same place.
An uptime monitor is not a substitute. Pingdom describes itself as a website monitoring service, with uptime checks from "100+ locations worldwide" and transaction monitoring. On the home page we read on October 25, 2026 we found no mention of cron jobs or heartbeat checks. A probe asks a URL whether it is alive. A background job exposes no URL, so there is nothing for a probe to ask.
If your stack already runs Prometheus, you may be tempted to build this yourself with metrics. In our view that is more work than it looks: you would write the alert rules for absent data yourself, including the case where the machine that should report is off. A heartbeat tool is built around exactly that case.
When email alerts from cron are enough
Skip the extra service if a job is trivial, its output is quiet unless something breaks, the server has a working mail setup and you read that inbox. MAILTO is built into cron and costs nothing. The failure it cannot cover is, in our view, the one that matters most: a machine that is off, or a cron daemon that isn't running, sends no mail at all.
A sensible split, in our view: use a heartbeat for anything whose absence would hurt a customer or a deadline, like backups, invoices, data syncs and renewals. Leave low-stakes cleanup on plain email.
Your next step
Pick the one scheduled job whose silence would cost you most. Create a check for it, add the ping with the two-ampersand pattern, set the grace time above its slowest run, and break it once to see the alert. Then work down the list. If you want to compare other tools first, browse the Testing & Monitoring category, and see our guide to SSL certificate monitoring tools for another thing that fails silently on a schedule. Developer tooling more broadly sits in Developer Tooling.
Prices and plan limits above are as listed on the vendors' pages on October 25, 2026 and change often. Check the current page before you buy.
Frequently asked questions
How do I monitor a cron job?
Give the job a ping at the end, joined with two ampersands so it runs only when the job exits with code 0. Register the schedule and a grace time with a heartbeat service. If the ping doesn't arrive on time, the service sends the alert, even when the whole machine is down.
What is heartbeat monitoring?
Heartbeat monitoring, which the Healthchecks.io docs also call a dead man's switch, makes the job send a signal to the monitor instead of the monitor probing the job. If the expected signal is missing at the expected time, the monitor raises an alert on its own.
What is a grace period in cron monitoring?
Grace time is the extra wait before an alert when a check is late, on top of the expected period between pings. Healthchecks.io advises setting it above the job's expected duration, and its example uses 30 minutes for a job that takes 15 to 25 minutes.
Why did my cron job not run and send no error?
Cron produces no message when the machine is off, the daemon is stopped or the configuration is invalid. Healthchecks.io lists those among the failures a missing ping detects, along with non-zero exits and abnormally long runs. Email via MAILTO cannot report any of them.
Is MAILTO enough to monitor cron?
Only for simple cases. Healthchecks.io notes that MAILTO needs a configured mail server, sends nothing if the machine is powered off or offline, and emails on every run of a job that prints output, which can cause alert fatigue. It cannot tell you a job never started.
Can an uptime monitor watch my cron jobs?
Usually not. An uptime monitor probes a URL, and a background job has none. On its home page, read October 25, 2026, Pingdom mentions uptime and transaction monitoring but not cron or heartbeat checks. Use a heartbeat tool for scheduled work.
Products in this article
CronitorMonitoring for cron jobs, daemons and scheduled tasks with no setup
Healthchecks.ioCron job monitoring that alerts you when scheduled tasks stop running
PingdomWebsite uptime monitoring that alerts you when a site goes down
PrometheusCNCF-standard metrics collection and alerting, with an open-source time-series database
SentryCatch crashes and slow code with stack traces, replays and release context
About the author
Nihar Rout
CEO & Co-founder