Why cron failures stay hidden
Every other kind of failure produces evidence. A crashed process leaves a stack trace. A failing API returns a 500. A down website stops answering checks.
A cron job that stops firing produces the opposite: perfect silence. The most common causes are all silent by nature.
- The server was rebuilt and the
crontabwas never restored. - The user the job ran as was removed, or its credentials expired.
- The script moved, was renamed, or lost its execute bit — cron logs it somewhere nobody reads.
- The container hosting the scheduler was scaled to zero.
- The job is still running, but hung on a lock it will never get.
In every one of these cases your dashboards stay green, because there is nothing to see. You find out when somebody asks where last week's report went, or when a backup you finally need turns out to be eleven days old.
The fix: watch for the ping that doesn't arrive
This pattern is called a dead man's switch. Instead of us checking your job, your job checks in with us. You say how often it should report, and we alert you when it goes quiet.
-
Create a heartbeat monitor
Give it a name and say how often the job should run. You get back a unique ping URL.
-
Add one line to your job
Call that URL when the work finishes successfully. Any HTTP client will do — the endpoint accepts both
GETandPOST.# crontab — ping only if the backup actually succeeded 0 3 * * * /usr/local/bin/backup.sh && curl -fsS -m 10 \ https://pulse.pulsecima.com/heartbeats/ping/YOUR-PING-TOKENThe
&&is the important part. If the script exits non-zero the ping is skipped, the heartbeat goes quiet, and you get alerted — so this catches a job that runs and fails, not only one that never starts. -
Get an email when the ping stops
We evaluate every minute. Once the expected interval plus your grace period has passed with no ping, the monitor flips to down and you are notified.
What you configure
| Setting | What it means |
|---|---|
| Expected interval | How often the job should ping. A nightly backup is 86400 seconds; a five-minute sync is 300. |
| Grace period | How late is still acceptable before we call it down. Defaults to 300 seconds. Set it wider than the job's normal runtime variance so a slow night doesn't wake you. |
| Webhook URL (optional) | A Slack-compatible incoming webhook, if you want the alert in a channel as well as your inbox. |
A monitor is late once last ping + expected interval + grace period
has passed. Nothing else affects that decision.
Works with whatever runs your jobs
Shell script, wrapping a command you already have
#!/bin/sh
# do the work first; report only if it succeeded
if /opt/reports/generate.py; then
curl -fsS -m 10 https://pulse.pulsecima.com/heartbeats/ping/YOUR-PING-TOKEN
fi
GitHub Actions scheduled workflow
on:
schedule:
- cron: "0 6 * * *"
jobs:
nightly:
runs-on: ubuntu-latest
steps:
- run: ./scripts/nightly.sh
- name: Report heartbeat
run: curl -fsS -m 10 "$PING_URL"
env:
PING_URL: ${{ secrets.PULSECIMA_PING_URL }}
Python, at the end of a task
import urllib.request
run_the_job()
urllib.request.urlopen(
"https://pulse.pulsecima.com/heartbeats/ping/YOUR-PING-TOKEN", timeout=10
)
The token in the URL is the credential, so the ping needs no API key — which is what keeps
it to a single curl in a cron line. Treat the URL like a secret and keep it out of
public repositories.
What happens when a job goes missing
One alert, not a stream
The monitor flips to down and sends a single email, plus a webhook message if you configured one. It stays down without re-alerting until a ping arrives again, so a job that has been broken for a week does not fill your inbox with duplicates.
The next successful ping clears it
Any ping sets the monitor back to healthy. If the job breaks again later, you are alerted again.
Limits worth knowing before you sign up
We would rather you read these now than discover them during an incident.
- Monitoring starts at the first ping. A monitor you create but never ping stays in a new state and will not alert. Run the job once, or open the ping URL by hand, to arm it.
- Detection granularity is one minute. We evaluate every 60 seconds, so an alert can land up to a minute after the deadline passes.
- Email and webhook only. There is no SMS or voice alerting. Pro adds PagerDuty and on-call escalation, but those apply to URL monitors.
- Heartbeat monitors need a paid plan. Basic includes 5 and Pro is unlimited. The Free plan includes none — it covers 3 monitored URLs instead.
- We measure whether the ping arrived, not what the job did. A job that finishes and pings while quietly writing an empty file still looks healthy to us.
It is the same account as your uptime monitoring
Heartbeat monitors are not a separate product with a separate bill. The same account also monitors your URLs from three independent regions, where an incident is confirmed only when at least two of the three agree — so one flaky region does not wake you at 3 a.m. That part is included on every plan, Free included.
See how the URL monitoring works →
Questions people ask
What exactly is a dead man's switch?
A check that fires when a signal stops. Ordinary monitoring asks "is this responding?" and needs something to reach out to. A scheduled job has no address to poll, so the job reports in instead, and the absence of that report becomes the alarm.
My job runs at irregular times. Will this work?
Set the expected interval to the longest gap you would still call normal, and lean on the grace period. If a job legitimately runs anywhere from hourly to daily, a heartbeat can only catch the daily case without false alarms — that is a limitation of the approach itself, not just of this implementation.
Does a failed job alert me, or only a missing one?
Either, if you gate the ping on success as shown above. Because the ping fires only when your command exits zero, a job that runs and fails looks the same as one that never ran, and both alert you.
Do I need an API key for the ping?
No. The token in the URL is the credential, which keeps the cron line to one
curl with no headers to manage.
Can I ping from a machine with no outbound internet access?
No. The job has to reach pulse.pulsecima.com over HTTPS. If your batch host is
fully isolated, a heartbeat cannot reach us and this will not work for that job.
Stop finding out days later
Create an account, add a heartbeat monitor, and paste one line into your crontab. If a job stops running, you will know the same day.
Heartbeat monitors are not part of the Free plan; Basic starts at $1.49/month. See pricing →
Start free