Heartbeat & cron jobs
Get alerted when a scheduled job or background worker doesn't check in.
Most monitors reach out and test your systems. A heartbeat monitor works the other way around: your job, script or worker pings WatchFor when it runs — and WatchFor alerts you when the ping doesn't arrive on time.
That inversion catches the failures outbound checks can't see: a nightly backup that silently stopped, a cron entry lost in a server migration, a queue worker that crashed, a certificate-renewal script that never fired.
Two schedules, one monitor type
When creating the monitor you pick how the pings are expected:
| Mode | Use it for | You set |
|---|---|---|
| Every interval | Workers and services that check in continuously ("every 5 minutes") | The interval + a grace period |
| Cron schedule | Jobs that run at specific times ("03:00 daily") | A standard 5-field cron expression, its timezone + a grace period |
The grace period is how late a ping may arrive before WatchFor alerts — set it to absorb normal runtime variance (a backup that takes 10–40 minutes deserves more grace than a heartbeat that fires every minute).
The ping URL
Each heartbeat monitor gets a unique ping URL, shown on its detail page:
https://ingest.watchfor.io/p/<your-token>- Any HTTP method works —
GET,POST,HEAD, whatever your tooling sends. - The URL token is the only secret — treat it like a password. Anyone with the URL can ping the monitor.
- An optional request body (up to 10 KB — e.g. the job's last log lines) is stored with the ping.
Signal endpoints
| URL | Meaning |
|---|---|
/p/<token> | Success — the job completed fine |
/p/<token>/<exit-code> | Report the exit code: 0 = success, anything else = the run failed |
/p/<token>/fail | Explicit failure report |
/p/<token>/start | The job just started — pairs with the finish ping to measure run duration |
A failure ping still counts as a check-in — it tells WatchFor your scheduling machinery is alive, so you get a "run failed" alert instead of a misleading "missed schedule" one.
Examples
At the end of a cron line — the ping only fires if the job succeeded:
0 3 * * * /usr/local/bin/backup.sh && curl -fsS https://ingest.watchfor.io/p/<token>Report the real exit code, whatever it is:
/usr/local/bin/backup.sh; curl -fsS https://ingest.watchfor.io/p/<token>/$?Capture the job's output and attach it to the ping — it's stored with every ping (success or failure, up to 10 KB) and shown in the monitor's Pings log:
OUT=$(/usr/local/bin/backup.sh 2>&1)
curl -fsS --data-raw "$OUT" https://ingest.watchfor.io/p/<token>/$?Send a start/finish pair correlated by a run ID (rid) — WatchFor measures
each run's duration, shows it per ping, and charts it over time:
RID=$(uuidgen)
curl -fsS "https://ingest.watchfor.io/p/<token>/start?rid=$RID"
/usr/local/bin/backup.sh
curl -fsS "https://ingest.watchfor.io/p/<token>/$??rid=$RID"Already using Healthchecks-style pings? The URL conventions are compatible — migrating is usually just swapping the domain in your existing curl lines.
Alerting
New heartbeat monitors come with two preset alert rules:
- Missed schedule (critical) — no ping arrived within the expected window plus grace.
- Run failed (warning) — a ping arrived but reported a non-zero exit code
or hit the
/failendpoint.
Two more presets can be enabled on the monitor's Alerting tab:
- Specific exit code — alert on one exact code, e.g. 137 (killed / OOM) or 124 (timeout).
- Run duration — alert when a run takes longer than a threshold (requires start/finish ping pairs).
Incidents, notifications and status pages work exactly like any other monitor type.
Good to know
- No locations to pick — your systems ping WatchFor, so the multi-region location selection other monitors use doesn't apply here.
- A
/startping doesn't count as the check-in — the finish ping does. Resetting the schedule on start would make a job that hangs mid-run look healthy. - A failed delivery of your ping (network blip on your side) looks the same
as a missed run — prefer
curl -fsS --retry 3in critical jobs. - Pausing the monitor stops the schedule expectation; pings received while paused are simply ignored.