Monitoring cron jobs and background workers via heartbeat
· 6 min read
In brief: Classic HTTP monitoring won't detect that your nightly cron sending invoices or syncing data has fallen. The heartbeat pattern reverses the direction of communication - the cron reports to monitoring, and if it doesn't call at the expected time, you get an alert.
In brief: Classic HTTP monitoring won't detect that your nightly cron sending invoices or syncing data has fallen. The heartbeat pattern reverses the direction of communication - the cron reports to monitoring, and if it doesn't call at the expected time, you get an alert.
The problem: background tasks without an HTTP endpoint
A typical backend has paths:
- Web requests (HTTP/HTTPS to the server) - you monitor with an uptime check.
- Cron jobs (daily backup, monthly invoicing, hourly sync) - they have no HTTP endpoint, external monitoring doesn't see them.
- Workers (Celery, BullMQ, Sidekiq) consuming a queue - also no HTTP.
If the cron fails (you change crontab and make a typo, the server has no disk, an environment variable is missing, a dependency upgrade broke the import), nobody will warn you - until on Monday morning you notice that invoices weren't sent over the weekend.
Heartbeat pattern: cron pings monitoring
The principle is the opposite of normal monitoring:
- In the monitoring service you create a heartbeat monitor with an expected interval (e.g. "every 60 minutes").
- You get a unique heartbeat URL:
https://epulz.io/heartbeat/abc123xyz. - In your cron job at the end of a successful run you call this URL (HTTP GET or POST).
- If the ping doesn't arrive at the expected time (+ grace period), monitoring alerts you.
Practical example: bash cron
# /etc/crontab
0 3 * * * www-data /usr/local/bin/backup.sh && curl -fsS -m 10 \
https://epulz.io/heartbeat/abc123xyz > /dev/null
The key is the && - the heartbeat is sent only if backup.sh ends with exit code 0. If the script fails, the ping won't come, and within an hour you get an alert.
Tip: For more thorough coverage add a "start" heartbeat too:
curl -fsS -m 10 https://epulz.io/heartbeat/abc123xyz/start > /dev/null
/usr/local/bin/backup.sh
EXIT=$?
curl -fsS -m 10 "https://epulz.io/heartbeat/abc123xyz?exit=$EXIT" > /dev/null
Monitoring then distinguishes "started and didn't finish" (script froze) from "didn't start at all" (the cron job didn't run).
Python: requests + try/except
import os, requests
HEARTBEAT_URL = os.environ["HEARTBEAT_URL"]
def sync_data():
# your logic
pass
try:
sync_data()
requests.get(HEARTBEAT_URL, timeout=10)
except Exception as e:
# Heartbeat is not sent - monitoring will alert you
raise
Node.js: async / await
const HEARTBEAT_URL = process.env.HEARTBEAT_URL;
async function nightlyJob() {
await processInvoices();
await fetch(HEARTBEAT_URL, { signal: AbortSignal.timeout(10000) });
}
nightlyJob().catch(err => {
console.error(err);
process.exit(1);
});
Grace period: how much time to give before alert
Heartbeat monitor needs tolerance - cron sometimes runs longer than usual, the network has latency, NTP sync might be slightly shifted. Grace period is the time after the expected interval during which monitoring still waits.
Practical values:
- Hourly cron: interval 60 min + grace 10 min
- Daily backup (averages 20 min): interval 1440 min + grace 60 min
- Weekly report: interval 10080 min + grace 360 min (6 h)
Grace too tight = false-positive alerts. Too loose = delayed warning when it really falls.
Where the heartbeat pattern helps most
- Nightly DB backups
- Sync with external APIs (CRM, accounting, payment)
- Report calculations
- Cleanup tasks (deleting old sessions, logs, temporary files)
- Healthcheck cycle of long-running workers
- Scheduled emails, newsletters, invoicing
Conclusion
Background tasks are often more critical than the web itself, yet they remain a blind spot of monitoring. The heartbeat pattern takes 5 minutes to implement (adding curl at the end of a cron line) and provides the same peace of mind as uptime monitoring for the frontend.
Start monitoring cron jobs
ePulz.io supports heartbeat checks with a configurable grace period. 7 days free.
Try ePulz.io free - 7 days, no credit card needed.
Create account