A heartbeat tells you the job ran. It does not tell you the dump took 3 minutes last week and 47 minutes tonight.
I already POSTed after a successful backup. Adding a small JSON body on that same request was enough to keep duration and size next to the ping — without standing up metrics infra.
Empty POST still counts. JSON is optional. Nested objects and log blobs are dropped on purpose. This is not log storage.
Ping only on success, with a few scalars
# After backup.sh succeeds
curl -fsS -X POST https://www.gonewatch.com/api/heartbeat/YOUR_TOKEN \
-H "Content-Type: application/json" \
-d '{"duration_ms":184320,"bytes":2147483648,"tables":42}'
Keys are yours. Typical ones from real jobs:
- duration_ms — how long the run took
- bytes — how big the artifact was
- tables / rows / failed — whatever you already print at the end of the script
- Same idea in Node or Python: POST JSON, top-level numbers and strings only.
What you get
Last values on the monitor, plus a sparkline for each numeric field.
duration_ms shows as time (184320 → 3m 4s). bytes shows as size (2147483648 → 2 GB). Other numbers stay grouped digits.
If a key is nested, an array, or too large, that key is ignored. The ping still records. The job is still “up.”
What not to send
Stdout, HTML, the backup file, PII, secrets. Keep the heartbeat URL itself secret — it is the credential.
One URL per job still holds. Dump, file sync, and offsite copy are three different stories. Mixing them into one payload will not tell you which part got slow.
Where I put it
I wired this into Gonewatch so the same monitor that alerts on silence also keeps last values and charts. Free to start.
Top comments (2)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.