← Backup Verification Evidence

This checker vs. Healthchecks.io

Two different questions about the same backup. Healthchecks.io asks did the job run and report success on time? This asks is the file it left behind actually usable? A truncated archive answers yes to the first and no to the second, which is the whole reason this page exists.

What each tool is for

Healthchecks.io is a cron-job and scheduled-task monitoring service, also available as open-source software you can host yourself. The pattern is a dead man's switch: your job sends an HTTP ping to a unique URL when it starts, succeeds, or fails, and if an expected ping does not arrive inside its grace period the service raises an alert through whichever channels you have configured. It is very good at the failure modes that make a job produce nothing — the box that never came back, the cron entry someone commented out, the script that died on a non-zero exit. Its current plans, limits and prices are not reachable from this page and none are invented here; only its well-documented category is described.

This checker does none of that. It has no scheduler, no hosted component, no account and no notification channel, and it will never tell you that a job failed to start — if nothing ran, there is nothing here to look at. What it does instead is read the evidence a run left behind: whether the exit code and the artifact stat agree with what you said to expect, whether the archive reads back when you ask for an integrity check, and whether tonight's file is meaningfully smaller than the nights before it. It reports one of four states — verified, suspicious, failed, or inconclusive — and never folds an ambiguous run into "looks fine."

QuestionWhere to answer it
Did last night's backup job run at all?Healthchecks.io, or comparable cron monitoring — this checker cannot see a job that never executed.
Did the job exit non-zero, or stop pinging?Healthchecks.io, or comparable cron monitoring.
The job exited 0 — did it actually write a usable archive?This checker, free and local.
Is tonight's archive quietly smaller than the last few nights?This checker's night-over-night trend view.
Does the archive read back intact, not just exist?This checker's verify, which reads the artifact rather than trusting its stat.
I need someone paged at 3am when the switch trips.Healthchecks.io, or comparable cron monitoring — this checker sends nothing.
I need a dated, portable record for a client SLA or an insurance questionnaire.This checker's JSON handoff.

The gap, concretely

The reason these two are complements rather than substitutes is a failure mode that is common and quiet. A destination fills up, or a pipe breaks halfway, or a tar writes a partial file — and the script still reaches its last line and still exits 0. It therefore still sends its success ping, and the monitoring dashboard is still green. Nothing in the schedule layer is in a position to notice, because from its point of view the job did what it said it would.

That run is what this checker reports as suspicious: the exit code says success, but the artifact stat disagrees with what you expected, or the file is a fraction of the size it has been every other night. The trend view exists for the slower version of the same problem, where an archive shrinks a little each week and no single night looks wrong on its own.

None of this is a restore test. A file that stats correctly and reads back without error can still be missing the data you actually need. Only a real test restore tells you that, and this tool says so rather than implying otherwise.

Using both together

The two layers compose without either one having to know about the other. Run the backup, run the evidence check over what it produced, and only ping your monitor if both succeeded. verify exits 0 when every artifact read back intact, 1 when any is provably corrupt, and 2 when nothing is corrupt but something could not be checked — so an && is enough, and an archive that could not be read is treated as a reason not to report success rather than as a pass:

#!/bin/sh
set -e
restic backup /srv --tag nightly
PYTHONPATH=src python3 -m backup_evidence.cli verify \
    --max-age-hours 26 /backups/nightly.tar.gz \
  && curl -fsS --retry 3 "$PING_URL"

Your existing monitor is unchanged, but its green now means something stronger than it did: not merely "the script finished", but "the script finished and left an archive that is the size it should be." A truncated backup no longer pings at all, so the dead man's switch trips — which is the alerting you already have, finally pointed at the right event.

Open the verification checker to run this against backups you already have, or the trend view to compare consecutive nights in your browser.

Common questions

Should I use this checker or Healthchecks.io?

They answer different questions, and a team that cares about backups usually ends up wanting both. Healthchecks.io is a cron-job monitoring service: your scheduled job sends an HTTP ping when it starts, succeeds, or fails, and if an expected ping does not arrive within its grace period the service alerts you through email, chat, or an on-call integration. It is the dead-man's-switch layer — it catches the job that never ran, the machine that never came back, and the script that exited non-zero. This checker never watches a schedule and sends no alerts. It looks at what a run left on disk: whether the exit code and the artifact stat agree with what you expected, whether the archive reads back intact if you asked it to, and whether tonight's file is quietly smaller than the nights before it. The blind spot each covers for the other is concrete: a backup that fills the disk and writes a truncated file still exits 0, so it still pings, so the monitor still shows green. That run is exactly what this checker reports as suspicious rather than verified.

Does this checker replace cron monitoring?

No, and it is not trying to. It has no scheduler, no notification channel, no hosted component, and no way to notice that a job failed to run at all — if nothing executes, this tool has nothing to look at and will not tell you anything is wrong. That absence is precisely what a dead-man's-switch service like Healthchecks.io exists to catch. Run one for the schedule, and this for the artifact the schedule produced.

Can I run this from the same cron job that pings my monitor?

Yes, and that is the intended shape. Both subcommands exit non-zero unless the result is clean: verify exits 0 only when every artifact read back intact, 1 when one is provably corrupt, and 2 when nothing is corrupt but something could not be checked at all; check exits non-zero when the newest run record is anything other than verified. So you can chain either one before your ping — run the backup, run backup-evidence over the artifact it wrote, and only signal success to your monitor if the evidence check also passed. Your existing monitor then stops meaning "the script finished" and starts meaning "the script finished and left a plausible archive" — without changing anything about how the monitor itself is configured.

Is this page affiliated with Healthchecks.io?

No. This site is not affiliated with, endorsed by, or sponsored by Healthchecks.io or its authors. Healthchecks.io is named here only to describe what this checker is and is not, and no claim is made about its current pricing, plans, or feature set beyond the well-documented category it belongs to: cron-job and scheduled-task monitoring by HTTP ping.