# monitor.heartbeat The state of a heartbeat check (a "dead man's switch"): a cron job, backup or worker pings the monitor each time it runs, and the monitor raises the alarm when the pings stop. This is the shape healthchecks.io, Cronitor and Uptime Kuma's push monitors use, with healthchecks.io's vocabulary: | state | healthchecks.io says | here | | --- | --- | --- | | `new` | "A newly created check that has not received any pings yet." | `lastPingAt` is null | | `up` | "The last success signal has arrived on time." | `now <= dueAt` | | `late` | "The success signal is due but has not arrived yet. It is not yet late by more than the check's configured Grace Time." | `dueAt < now <= downAt` | | `down` | "The success signal has not arrived yet, and the Grace Time has elapsed." | `now > downAt` | where `dueAt = lastPingAt + intervalSeconds` and `downAt = dueAt + graceSeconds`. The due second itself is still up, and the last second of the grace time is still late; the state changes the second after. With no grace time a check goes straight from up to down. `overdueSeconds` is `now - dueAt` when late or down (how long past due, for "late by 2m" in an alert), and 0 otherwise. `dueAt` and `downAt` are returned so the caller can schedule its next evaluation instead of polling. ## Edge cases - A ping stamped after `now` (the job's clock is ahead of the monitor's) is `up`, overdue 0: its due time is later still. It is not an error, because clock skew is normal and refusing it would hide a healthy job. - `paused` is not a state here: pausing is the caller's decision, not something the ping times say. - Only simple period schedules are covered; a cron-expression schedule gives `dueAt` from the expression instead. ## Errors - `intervalSeconds must be at least 1, received X` - `graceSeconds must not be negative, received X` - `NAME must be whole seconds, received X` for a fractional time ## Sources - healthchecks.io documentation, "Check states" and "Period and Grace Time": https://healthchecks.io/docs/ and https://healthchecks.io/docs/configuring_checks/