Heartbeat Monitoring for Jobs That Fail Silently
A heartbeat check is a dead-man's-switch for a scheduled job. Your job pings a URL every time it finishes; if a ping does not arrive within its interval plus grace period, Nivaronix opens an incident. It catches the failure that ordinary monitoring cannot see — the run that never happened.
Last updated August 12, 2026.
Why silent failure needs its own kind of check
Ordinary monitoring answers a question about something that exists: is this site reachable, is this certificate still valid, is this DNS record still correct. It works because there is something to go and look at. A scheduled job has no such surface. A nightly backup that silently stopped running three weeks ago looks exactly like a nightly backup that ran perfectly, right up until the moment you need the backup.
A heartbeat check inverts the question. Instead of Nivaronix reaching out to your job, your job reports in to Nivaronix. Silence is the signal. If the report does not arrive on time, that absence is what opens the incident.
What a heartbeat check does not do
A heartbeat check watches whether your job reported in — not whether it did its work correctly. It never sees the job, its logs, its output, or its exit code; it only knows whether a ping arrived inside the window you configured. A backup script that runs on schedule, writes a zero-byte archive, and pings anyway is a healthy heartbeat check. Heartbeats catch the run that did not happen. They do not audit the run that did.
What people watch with them
Anything scheduled, unattended, and quiet when it breaks — nightly backups, cron jobs, ETL runs, queue workers, certificate renewal jobs.
Interval and grace period
A check is configured with exactly two numbers, and both mean precisely what they say:
- Expected interval
How often the job is expected to ping. A whole number of seconds, and at least 60 — the API rejects anything shorter or non-integer rather than quietly rounding it.
- Grace period
Slack added on top of the interval before silence counts as missed. Zero or more seconds; it defaults to zero. This is what absorbs a job that runs a little late without paging anyone — a nightly backup whose runtime drifts by twenty minutes should not be an incident.
The deadline is the last ping plus the interval plus the grace period. Nothing else feeds into it: no averaging, no learned baseline, no adjustment based on past behaviour.
The four states a check can be in
| Status | What it means |
|---|---|
| Pending | Created, but no ping has ever arrived, and the first window has not elapsed yet. A check nobody has reported to is honestly labelled as such, not shown as healthy and not backfilled with a plausible-looking timestamp. |
| OK | The last ping arrived within the expected interval. |
| Late | The interval has passed but the grace period has not. The job is overdue and visible as overdue — no incident yet. |
| Missing | Interval plus grace period have both elapsed with no ping. This is the state that opens an incident. |
Status is calculated at read time from the last ping and the check's own configuration, not stored on the row and refreshed on a timer. A status you are looking at is never older than the request that fetched it.
What happens when a heartbeat is missed
Your job pings on every run; a scheduled sweep evaluates each check against its deadline, and one incident opens exactly once per missed window. When a ping finally arrives, the incident resolves itself. The mechanics of each step are covered under “Go deeper” below.
The ping URL is a credential
Each check has one ping URL whose only identifying component is a long, randomly generated, URL-safe token. It is never sequential and never derived from your account, your asset, or the check's name.
The endpoint takes no authentication headers and no request body, and accepts either GET or POST, so a plain curl line at the end of a shell script, a cron entry, or a CI step is enough to wire it up. A successful ping returns a small JSON acknowledgement.
Treat it like an API key
Treat the ping URL as a credential. The token in it is the only thing the endpoint checks, which means anyone holding that URL can report a successful run on your behalf — and a heartbeat that is being pinged by the wrong party is a heartbeat that will never tell you your job stopped. Keep it in the same place you keep API keys: environment variables, a secrets manager, or your CI secret store. Not in a public repository, a shared wiki page, a screenshot, or a support ticket.
- The token is returned once, when the check is created, and again when it is rotated — the same posture as an API key. Copy it into your job at that moment.
- If a ping URL is exposed, rotate the token. Rotation issues a new one immediately and permanently invalidates the old — which also means every job still calling the old URL stops being heard from, so update them in the same change.
- A request bearing a token that matches no check gets a flat not-found response, identical whatever the reason. The endpoint is public, so it is deliberately not usable to probe whether a given token exists.
- Each token has a generous per-token request ceiling — well above what a job pinging once per interval needs, and there to keep a misconfigured or retrying script from hammering the endpoint.
Setting one up
- Create the check against one of the assets in your account, give it a name you will recognise in an alert — "Nightly backup job" rather than "hb-1" — and set its interval and grace period.
- Copy the ping URL returned at creation into your job, as the last thing the job does on a successful run. Putting the ping at the end, after the work, is the point: a ping fired at the start reports that the job started, not that it finished.
- Leave it. A heartbeat check is never polled and costs nothing to hold until it misses.
How many checks each plan includes
| Plan | Heartbeat checks |
|---|---|
| Free | 2 |
| Starter | 5 |
| Pro | 20 |
| Studio | 100 |
| Scale | 250 |
Heartbeat checks are counted separately from monitors and do not consume your monitor allowance, because a heartbeat check is never polled — it costs nothing to hold until it misses. The limit is enforced when a check is created.
Go deeper
Everything above is the whole story at a glance. Open any of these for the detail behind it.