heartbeetsign in

monitor a backup script

nobody notices a backup that stopped running; you notice the day you need it. this is the founding use case of the silence monitor (the classic dead-man's switch): the job itself proves it ran, and silence pages you.

the one-line version

#!/usr/bin/env bash
set -euo pipefail

pg_dump mydb | gzip > /backups/mydb-$(date +%F).sql.gz

# only reached if the dump succeeded — that's the point.
curl -fsS -X POST https://heartbeet.page/nightly-db-backup \
  -H "Authorization: $HEARTBEET_API_KEY"

put the curl at the end of the script, after set -e: the heartbeat only fires when everything before it succeeded. a backup that crashes halfway sends no heartbeat, and silence is exactly what the beets page on. no hint needed: a nightly job fits inside the default cold-start window, so even the very first night has a sane deadline, and from the second heartbeat the real rhythm takes over.

why this catches what logs don't

  • cron silently skipping the job (commented out during an incident, never restored): no heartbeat, you're paged.
  • the machine itself is down or wedged: no heartbeat, you're paged (the monitor doesn't live on the box it watches).
  • the dump takes longer and longer each night: on a paid plan the beets automatically warn you about the arrhythmia, before the night it doesn't finish at all.
  • someone "temporarily" disables backups before a migration: pause it properly instead (POST /pause/nightly-db-backup?wait=6h) and the beets resume watching afterwards on their own.

a restore check, while you're here

a backup you've never restored is a hope, not a backup. if you have a weekly restore-test job, give it its own heartbeat (with ?hint=weekly on the first one, since weekly is slower than the cold-start window); now both halves of the promise are under the beets' watch.

the failure-shaped variant

if you'd rather send a heartbeat at the start and assert completion separately, split it into two jobs (backup-started, backup-finished): the second going quiet while the first stays lively is a precise "it runs but never finishes" signal, and tags (?tag=backups) keep them grouped on the dashboard. jobs are unlimited on every plan, the free one included, so splitting one job into two costs nothing.

next