Set up healthchecks.io heartbeat monitoring (overnight visibility): igor-ticking + task-finished pings #297
Labels
No labels
Agent
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
joshtronic/igor#297
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
Last night the tick timer sat stopped for ~8.5 hours and nothing surfaced it — we only caught it because I went looking this morning. We need a dead-man's switch: if igor stops ticking (or a tick hangs mid-task), you get paged, instead of silence. monit can't cover this —
agent.serviceis a per-minute oneshot, not a long-running process monit can watch; a periodic-ping heartbeat is the right tool for a cron job.Set up self-hosted healthchecks on the monitoring server and wire two pings out of the tick.
The two checks (your framing → healthchecks mechanics)
A. "igor is ticking" (heartbeat / dead-man's switch) — ping at the start of every tick. Since ticks fire every minute, this doubles as your "igor starting" signal and the liveness alarm: set period ~1 min, grace a few min, and if healthchecks hears nothing it alerts you. This is the piece that would have caught last night.
B. "finishing a task" — ping when a tick completes real work (a genuine
# OUTCOME, not a no-op idle tick). Best as a start→success pair around the work: send/startwhen ado_*_tickbegins working and the success ping when it returns. Then a tick that starts a task but never finishes (a crash/hang — the exact #291 pattern we just fixed) shows up as "started, never completed," and you get per-task duration too.Work split
You (this ticket — the server + config):
.envat~/.local/share/agent/.env.Harness code (a follow-up bot PR once the URLs exist — I can take this):
lib/healthcheck.shhelper, e.g.hc_ping <which> [start|success|fail].curltimeout,|| true, runs even during a Claude cooldown (it's non-model). A ping must NEVER affect tick outcome.tick.sh; task start/success around the cascade's work path..envmust match or the pings silently break (same rule as the SMTP2GO rename).Done when
healthchecks is up, igor is pinging it, and a deliberately-stopped timer (or a hung tick) raises an alert to you within the grace window — i.e., it would have caught last night. Then we greenlight the code half (add the
Agentlabel / split the follow-up) once the URLs are in.env.Notes
lib/healthcheck.sh, opt-in) #348lib/healthcheck.sh, opt-in) #348lib/healthcheck.sh, opt-in) #348Setup note (env var to add) — the code half is done (#348), this is the operator half
The heartbeat wiring is live and no-ops until you set the URL, so just add one env var to
~/.local/share/agent/.env:That's the dead-man's switch — the harness pings it at the top of every tick, and healthchecks.io alerts you if the pings stop.
Optional second check (catches a hung tick, not just a stopped one — pings start/success/fail around the work):
healthchecks.io check config
Set Period 30m / Grace 5m (≈35 min tolerance). Why 35 and not tighter: the heartbeat fires per-stage, and the longest single stage (a build, or the security-gate review) is ~30m — so a healthy tick can legitimately be silent up to ~30m. (This is now safe at 35m because the mid-tick heartbeat landed in #360/PR#362; before that a tick could go ~55m and you'd have needed ~60m.) 35m catches a real stoppage fast without false-paging a legit long build.
Notes
tick.shsources.envat the top of every tick, so it takes effect on the next tick (~1 min)..envonly (it's a bearer secret; don't commit it).All wired up, good to go!