Repository navigation
CI: workflow canary → PagerDuty for failed/stalled scheduled workflows - #451
Conversation
Co-Authored-By: Claude Code <noreply@anthropic.com>
Dry-run classification evidence
So I ran the exact classify step script (extracted verbatim from this workflow's Would-send events (dry-run output of the send step): Not all four are healthy today. Monitor and Project show as healthy because the latest completed run across events is the post-fix manual dispatch (#449) — the designed "manual-dispatch success counts as healthy for the failed check" behavior; their stall clocks are fine (monitor's 12:40 schedule run is post-fix and green). The critical path and mirror-exclusion rules were verified locally with a stubbed Post-merge, the hourly schedule will run for real; a |
What this adds
.github/workflows/workflow-canary.yml— a scheduled sentinel that watches the repo's scheduled workflows viagh run listand pages PagerDuty (Events API v2, EU host) when one fails or stalls. Plaincurl+gh+jq; no LLM, no VPN. Hourly cron (50 * * * *),workflow_dispatchfor manual runs.Watched workflows (static table in the workflow — add a workflow = add a row)
monitor.ymlproject.ymlproduct.ymlvahter-mirror-reconcile.ymlClassification
cancelledskipped) concludedfailure/timed_out/startup_failure. A manual-dispatch success counts as healthy for the failed check.aks-vpnsharing does not count as fresh.Manual-dispatch handling decision: the failed check uses the latest completed run across events (so a manual-dispatch success makes the failed check green), while the stall clock resets only on schedule-event runs.
PagerDuty
dedup_keyper workflow:bots/<workflow-file>;triggeron failed/stalled,resolvesent unconditionally on healthy (resolving a dedup with no open incident is harmless). PD service hasauto_resolve_timeout = null, so every trigger has a matching resolve path.warningnormally; if ≥2 of the three agent workflows (monitor, project, product) are failed/stalled in the same poll, their triggers carryseverity: critical. Mirror Reconcile is warning only and never part of the critical count. When the count drops back to one, the next trigger for that key returns towarning.source=Szer/bots/<file>, one-linesummary(display name + state + run URL or "no run in N hours"),component= file,group=github-actions,custom_details= latest run id / conclusion / created_at / threshold.PAGERDUTY_ROUTING_KEY; if unset, printsPAGERDUTY_ROUTING_KEY not set, skippingand exits 0. Non-2xx from PD prints the response body and fails the step; no blind retries.if: failure()triggersbots/workflow-canary(warning); the first step of every run resolves that key.How to test
gh workflow run workflow-canary.yml --repo Szer/bots --ref <branch> -f dry_run=true— prints the classification table and every event that would be sent; sends nothing.test_event=warning-roundtrip,dry_run=false— sends one warning trigger + resolve onbots/canary-selftest. Never sends critical from a test path.dry_run=truedispatch, temporarily lower one agent workflow's threshold in the watch table (e.g. setmonitor.ymlto60|1m) so it goes stalled alongside another, and observeseverity=criticalin the printed would-send lines. Revert before merging.Notes
permissions: actions: readonly; no checkout, nocontents.timeout-minutes: 10,runs-on: ubuntu-latest.workflow_dispatchdefaults todry_run=true..github/bots.yml; no existing workflow touched. Optional in-workflowif: failure()hooks in the agent workflows are a separate follow-up.🤖 Generated with Claude Code