Heartbeat Monitoring: How to Know When Your Cron Jobs Fail
Cron jobs fail silently. No error page, no alert, no trace — they just stop running. Heartbeat monitoring catches this by inverting the check: instead of PingBase polling your service, your job pings PingBase. Silence is the alert.
The silent failure problem
Most monitoring tools watch your web-facing services: does your homepage load? Is your API returning 200s? These are outward-facing checks — if something breaks, the tool notices because it can't reach you.
Cron jobs and background tasks are different. They run on your infrastructure, on a schedule, without a public-facing endpoint. When they fail, there's nothing to check. No URL to poll. No HTTP response to inspect. The job just quietly stops doing its job.
Examples of what breaks silently:
- Nightly database backups — succeed for months, then fail because the disk is full
- Daily report emails — stop sending because a dependency changed
- Payment retry jobs — stop processing failed charges without anyone noticing
- SSL auto-renewal (Certbot) — fails due to a DNS change, certificate expires weeks later
- Search index rebuild — stops running, search results go stale
- Data sync jobs — external API changes, sync silently breaks
In each case, the job ran fine hundreds of times before. There was no deployment, no code change — it just stopped. And nobody found out until a user complained, a payment was missed, or a backup was needed and didn't exist.
How heartbeat monitoring works
Heartbeat monitoring inverts the normal uptime check. Instead of a monitoring service polling your URL, your job calls a URL that the monitoring service gives you.
The flow:
- You create a heartbeat monitor in PingBase and set an expected interval (e.g. every 24 hours)
- PingBase gives you a unique ping URL
- You add a single HTTP request to the end of your job — a GET or POST to that URL
- Every time the job runs successfully, it pings PingBase
- If PingBase doesn't receive a ping within the expected window, it alerts you
The elegance of this pattern: silence is the failure condition. You don't need to detect what went wrong — you just need to notice that the expected ping didn't arrive. This works regardless of why the job failed: crash, timeout, misconfigured cron, deploy that inadvertently disabled the scheduler, or a dependency outage.
What to monitor with heartbeats
A good rule: any scheduled task where missing a run has consequences is worth a heartbeat monitor. Here's a practical checklist:
High priority — monitor these first
- ● Database backups
- ● Payment processing / retry jobs
- ● SSL certificate auto-renewal
- ● Security scans or compliance checks
Medium priority
- ● Email digest / notification jobs
- ● Data sync and import jobs
- ● Search index rebuilds
- ● Analytics aggregation jobs
Lower priority (still worth it)
- ● Log rotation and cleanup jobs
- ● Cache warming jobs
- ● Expired session cleanup
Setting up a heartbeat monitor in PingBase
- Log in to PingBase and click Add monitor
- Select Heartbeat as the monitor type
- Give it a name (e.g. "Nightly DB backup") and set the expected interval (e.g. every 24 hours)
- Optionally set a grace period — how long after the expected interval PingBase should wait before alerting (useful for jobs with variable run times)
- Save — PingBase generates a unique ping URL for this monitor
- Add the ping call to the end of your job (see examples below)
The monitor starts in a "waiting" state. After the first successful ping, it becomes active and will alert you if a ping is missed.
Code examples
Shell / cron
# Run backup, then ping on success
/usr/local/bin/backup.sh && curl -fsS https://ping.pingba.se/hb_abc123 > /dev/null
Node.js
async function runNightlyJob() {
try {
await doTheWork();
// Ping on success
await fetch('https://ping.pingba.se/hb_abc123');
} catch (err) {
console.error('Job failed:', err);
// Don't ping — PingBase will alert after the grace period
}
}
Python
import requests
def run_backup():
try:
do_backup()
# Ping on success
requests.get('https://ping.pingba.se/hb_abc123', timeout=5)
except Exception as e:
print(f"Backup failed: {e}")
# Don't ping — PingBase will alert
GitHub Actions
- name: Ping PingBase heartbeat
if: success()
run: curl -fsS https://ping.pingba.se/hb_abc123 > /dev/null
The key pattern in all examples: only ping on success. If the job errors, skip the ping — PingBase will notice the silence and alert you after the grace period expires.
FAQ
What's a grace period?
Grace periods give your job extra time before PingBase considers it missed. If you have a job scheduled for midnight that typically finishes by 12:05am but occasionally takes up to 30 minutes, set a 30-minute grace period. PingBase waits until 12:30am before alerting — so you don't get paged for a slow-but-successful run.
What if my job runs multiple times a day?
Set the interval to match the shortest expected gap between runs. If a job runs every 6 hours, set a 6-hour interval. PingBase expects a ping every 6 hours and alerts if it doesn't receive one.
Can I ping from behind a firewall or VPN?
Yes. The ping URL is a simple outbound HTTP GET — as long as your server has outbound internet access (which almost all servers do), it will work. You don't need to open any inbound ports.
What happens if my job runs but the ping fails?
Treat this like a job failure — investigate why your server can't reach the ping URL. In practice, outbound HTTP from a server almost never fails. But if it does, the alert is still useful: something about your environment changed.
Start monitoring your cron jobs for free
Heartbeat monitors are included on all PingBase plans. Set up your first monitor in under 60 seconds — no credit card required.
Add a heartbeat monitor →