Heartbeats
Most monitoring tells you when something happens. A heartbeat tells you when something stops happening: the nightly backup that silently quit, the cron job that never ran, the server that dropped off the network. If you know the pattern as a dead man’s switch, this is it.
A heartbeat isn’t a separate object to manage: it’s a kind of topic. The watched thing checks in on a schedule with a single GET. If check-ins stop for longer than the topic’s interval (plus a grace period), Pinglet publishes an urgent alert to that same topic, so everyone subscribed to it gets a push, and the topic’s feed is the heartbeat’s history.
1. Create a heartbeat topic
In your namespace dashboard at pinglet.dev, open New topic and pick the type:
| Type | What it is |
|---|---|
| Push | The default. You publish messages to it. |
| Heartbeat | It watches for check-ins and alerts its own subscribers when one is missed. |
Choosing Heartbeat adds two more fields:
- Expect a check-in every: the interval, in seconds, minutes, hours or days,
- Grace period: slack before it fires. Optional; zero by default.
A topic’s type is fixed at creation, because it decides what the topic is. Heartbeats are created from the dashboard; POST /v1/{ns}/topics and publish-by-name both mint ordinary push topics.
2. Check in on a schedule
The topic’s page shows its check-in URL:
https://pinglet.dev/v1/ping/<token>
The token is the capability: no API key needed to check in. It is deliberately not the topic key: the check-in URL goes to the machine being watched, the subscribe link goes to people. Treat the check-in URL like a key. Editing the schedule doesn’t change it.
Have the watched thing hit the URL each time it does its job. For a cron job, append the ping to the command:
# crontab: nightly backup at 02:00, check in on success
0 2 * * * /usr/local/bin/backup.sh && curl -fsS https://pinglet.dev/v1/ping/<token>
The && matters: the ping only fires when the job succeeds, so a failing backup stops the check-ins and trips the heartbeat.
A healthy check-in returns 200 ok. An unknown token returns 404: a typo’d URL fails loudly instead of the heartbeat silently going dark.
A newly created heartbeat starts with a full interval already on the clock, so it can’t fire before the first check-in is even due.
3. What fires
- Down: once the interval + grace passes with no check-in, the topic flips to Down and publishes an urgent, error-level alert to its own subscribers; it breaks through Do Not Disturb like any urgent message.
- Recovery: the next successful check-in publishes a success-level “back to healthy” notice.
Each transition alerts once: a heartbeat that stays down doesn’t re-alert every sweep, and a recovery fires at most once even under concurrent check-ins.
Heartbeat alerts are system messages: they deliver even if your namespace has hit its monthly notification cap; being over quota shouldn’t hide the news that your backups stopped.
4. Watch and adjust it
On the dashboard, a heartbeat topic’s card reports its health in place of the usual last-message badge: OK, Down, or Paused. Its Settings page lets you:
- change the schedule: saving re-arms the clock from now, so widening an interval never leaves a heartbeat instantly overdue against its old deadline,
- pause and resume: a paused heartbeat never fires; resuming re-arms it with a fresh full interval.
Everything else works exactly as it does for a push topic: the same share link and QR code, the same public feed, the same subscription flow in the app. Whoever receives the alerts never has to know the topic is a heartbeat.
Ideas
- Backups: ping after a successful
pg_dump/restic run. - Cron & scheduled tasks: anything in a crontab or task scheduler.
- Hosts: a once-a-minute ping from a box that must stay up.
- People & processes: anything that should happen on a rhythm and quietly might not.