Skip to content

fix(visor): bound service-health probes so one dead endpoint can't stall visor state - #4241

Merged
0pcom merged 1 commit into
skycoin:developfrom
0pcom:fix/service-health-probe-timeout
Aug 27, 2026
Merged

fix(visor): bound service-health probes so one dead endpoint can't stall visor state#4241
0pcom merged 1 commit into
skycoin:developfrom
0pcom:fix/service-health-probe-timeout

Conversation

@0pcom

@0pcom 0pcom commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

ServiceHealth fans every /health probe out in parallel and wg.Wait()s on them. A single unresponsive endpoint — in practice a dmsg server whose /health does not answer over the discovery-routed path — blocked the whole call for the dmsg-HTTP client’s full ~10s timeout.

ServiceHealth is folded into the curated visor state snapshot, so the snapshot itself took ~10s. Under any additional load that tipped over callers’ RPC deadlines and the snapshot came back empty, which reads downstream as "zero routes / no legs" — a misleading artifact seen while debugging live route groups.

Bound each probe with a per-request context timeout (4s). A dead endpoint now costs at most that, not the underlying client timeout; healthy services (~300ms) are unaffected. Tests pin both the bound and the healthy path.

Evidence: on a live visor visor state was a consistent 10.6–10.8s (all individual health entries reported <600ms, yet the call hung — a goroutine dump showed ServiceHealth blocked in wg.Wait() on a dmsg-server version probe stuck in client.Get). With healthy probes at ~300ms, bounding that single hang returns the snapshot to sub-second; unit tests confirm the bound (a dead endpoint returns in ~4s, not the full client timeout). Live re-measurement to follow once the fleet updates.

…all `visor state`

ServiceHealth fans every /health probe out in parallel and wg.Wait()s on
them. A single unresponsive endpoint — in practice a dmsg server whose
/health does not answer over the discovery-routed path — blocked the whole
call for the dmsg-HTTP client's full ~10s timeout. ServiceHealth is folded
into the curated `visor state` snapshot, so that snapshot took ~10s and, under
any additional load, tipped over callers' RPC timeouts and came back empty —
which then reads downstream as "zero routes / no legs".

Bound each probe with a per-request context timeout (4s). A dead endpoint now
costs at most that, not the client timeout; healthy services (~300ms) are
unaffected. Adds tests pinning both the bound and the healthy path.
@0pcom
0pcom merged commit 71c75d5 into skycoin:develop Aug 27, 2026
10 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant