GitHub silently disables scheduled workflows on inactive repos and skips runs under load. A dead man's switch catches it from outside GitHub entirely.
GitHub Actions' schedule: trigger has a documented, easy-to-forget behavior: scheduled workflows are automatically disabled after 60 days of no repository activity — no commits, no PRs, nothing. If a repo just quietly does its job and nobody pushes to it, the cron simply stops, with a banner buried in the Actions tab that almost no one checks. Beyond that, GitHub explicitly documents that schedule events are best-effort: during periods of high load across GitHub's infrastructure, scheduled runs can be delayed by many minutes or dropped entirely for that interval, with no notification to the repo. A workflow can also be silently skipped if Actions billing is disabled, the workflow file has a YAML syntax error that only breaks the schedule trigger, or the schedule is defined on a non-default branch (GitHub only reads schedule: triggers from the default branch, a frequent surprise after a rename). None of these show up as a failed run in your history — they show up as no run at all, which is exactly the gap a ping-based check is built to catch.
Store your check URL as a repo secret (CRONCANARY_URL), then ping at the end of the job — only if every previous step succeeded:
Add an if: failure() step so a broken run alerts immediately instead of waiting out the grace period:
The failure step above only fires once the workflow has already been triggered. It can't help with the 60-day auto-disable, a mistyped cron expression, or a workflow file on the wrong branch — because in each of those cases GitHub never starts a run to report from. That's precisely why the check itself must be a scheduled expectation, independent of the workflow: set the check's Cron schedule to match on.schedule.cron, and a grace period generous enough to absorb GitHub's own delay under load (start with 15–30 minutes for anything time-sensitive). If the ping is late, the alert fires whether the cause was inside the workflow or GitHub silently never running it.
Every check has a public SVG badge that shows its live status (updates within ~1 minute). Paste this into any README — it doubles as a heartbeat anyone on the team can see:
Copy the exact markdown from your check's detail page. Add ?label=your-text to customize the left label.
Ready to wire this up? Create a free check — 20 checks, all alert channels, no card.