getNodi

Templates / Dead-man switch ping

A dead-man switch for your scheduler

This inverts the usual direction. Instead of something checking that your service is up, your job tells a watchdog it ran — and the watchdog alerts when the telling stops.

The recipe

Request
GET {{heartbeat_url}}
Schedule
Every 5 minutes (*/5 * * * *)
Timeout
10s
Attempts
3
Counts as success
2xx

You supply

Heartbeat URL
https://hc-ping.com/your-uuid

From healthchecks.io, Better Stack, Cronitor or similar.

Why this job exists

Every monitoring arrangement has a blind spot shaped like itself. A checker that polls your service cannot report that the checker is down. If the scheduler stops, the alerts stop with it, and silence is indistinguishable from everything being fine — which is precisely how it will be read.

Dead-man switches close that. The watchdog expects a signal at a known interval; the absence of the signal is the alert. It does not matter why the ping stopped — the process died, the network partitioned, the account lapsed, the schedule was disabled by mistake — because the failure mode being detected is silence itself.

Since the watchdog is a different provider on different infrastructure, an outage has to take out both to go unnoticed.

Setting it up

Create a check at healthchecks.io, Better Stack, Cronitor or similar. Each gives you a unique ping URL and asks for an expected period and a grace window. Set the period to match this cadence and the grace to a couple of intervals, so a single missed run is not an alert.

The useful placement is at the end of a pipeline rather than on its own. Have the last step of your nightly backup or your ETL ping the URL, and the watchdog then tells you the whole chain completed — not merely that something is scheduled.

Checking it actually works

  • Pause this job for longer than the grace window and confirm the watchdog actually pages you. An untested dead-man switch is an assumption.
  • Check the alert reaches somewhere you will see out of hours, which is when this fires.
  • Confirm the ping URL is the one for the check you think it is — they are opaque UUIDs and pasting the wrong one is easy and silent.

Where it goes wrong

Pinging when the work failed

If the ping runs unconditionally it reports "the schedule fired", not "the work succeeded". Most watchdogs accept a /fail suffix or a non-zero exit signal — use it, or the switch will faithfully report health while the job errors nightly.

A grace window that is too tight

Set to exactly the period, any jitter pages you. Two or three intervals is the usual compromise between noise and detection speed.

Watching the watchdog

This is a real regress and it ends somewhere. One layer is worth having; two is usually not. Stop at one and make sure its alert path is different from your primary one.

Questions

Why not have the watchdog poll my service directly?

Do both if you can — they answer different questions. Polling asks whether the service is reachable from outside; a heartbeat asks whether a specific piece of work completed, which polling cannot see.

Which provider?

healthchecks.io is open source and has a usable free tier; Better Stack and Cronitor bundle it with wider monitoring. The recipe is identical for all of them — it is a GET to a URL.

Can I point this at my own endpoint?

You can, but then it shares fate with your infrastructure, which defeats the purpose. The value comes from the watchdog being somewhere else.

Running it here

This is a preset in the product, not an illustration. Pick it in the dashboard, fill in the one value above, and the job is created, scheduled and enabled — with retries, a record of every run showing status, latency and response, and an alert the first time one fails. Secret values are encrypted at rest and never rendered back.

The free plan runs 3 jobs hourly and needs no card. Where a recipe wants a finer cadence than your plan allows, it is slowed to the fastest schedule you are permitted rather than rejected.