Skip to content

fix: report bandwidth check failures the same way the other HTTP checks do - #180

Merged
joshiste merged 1 commit into
mainfrom
fix/bandwidth-error-differentiation
Aug 6, 2026
Merged

fix: report bandwidth check failures the same way the other HTTP checks do#180
joshiste merged 1 commit into
mainfrom
fix/bandwidth-error-differentiation

Conversation

@joshiste

@joshiste joshiste commented Aug 6, 2026

Copy link
Copy Markdown
Member

Summary

Every kind of bandwidth-check failure (a transport error, a bad status code, a body-read error) previously collapsed into one generic error count, so a failed run gave no clue what actually went wrong - the metric said "N request(s) failed" and nothing else, and the chart couldn't tell a connection timeout apart from a 503.

The bandwidth check's metric and widget now report failures the same way the other HTTP checks (Requests/s, Fixed amount) already do:

  • Transport errors carry their real cause under error (e.g. "context deadline exceeded (2), connection reset by peer (1)"), driving the same Failure grouping.
  • Every response's status code is reported under http_status, with expected_http_status driving a new Unexpected Status grouping - identical field names to the per-request checks, generalized to a measurement window.

Test plan

  • go test ./exthttpcheck/... (including -race) passes
  • go build, go vet, gofmt -l clean
  • Verified live in demo-develop against a real target exhibiting connect timeouts and 5xx responses

@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown

Claude finished @joshiste's task in 3m 13s —— View job


Claude's PR Review

Todo list:

  • Check for previously unresolved Claude review threads and see if fixed (none found)
  • Gather context (diff, changed files, CLAUDE.md)
  • Review code quality, bugs, security, performance, race conditions
  • Post final review feedback

Summary

This is a well-structured change. The window-swap pattern in emitWindowMetric (capture the map references, then call resetWindowLocked() to point the struct fields at brand-new maps before unlocking) correctly avoids a data race — concurrent workers write to the new maps while the captured old maps are read lock-free after unlock. Pass/fail counting math is untouched, and the new tests (TestBandwidthChecker_ErrorDifferentiation, TestTransportErrorKey_CollapsesConnectionAddress) cover the new bucketing behavior well, including the ephemeral-port-collapsing rationale for transportErrorKey.

A few things worth double-checking, none of which I'd block on:

  1. Bad-status requests don't populate the error label (exthttpcheck/bandwidthChecker.go:224-234). recordBadStatus only touches windowStatusCounts/windowErrorCount, not windowTransportErrors, so a window with only non-2xx responses (no transport failures) won't set the error metric label and therefore won't match the "Failure" widget group — it falls through to "Unexpected Status" instead. This looks intentional (separating "never got a response" from "got a bad response"), and matches how the widget groups are ordered in bandwidth.go, but it's a behavior change worth confirming is the intended UX, since previously any error (including bad status) set the generic error label and hit "Error"/"Failure".

  2. PR description vs. implementation naming: the description mentions transport_errors and http_status_<code> as the label names, but the actual code reuses the existing error and a single aggregated http_status key (e.g. "200 (3), 503 (1)") rather than one label per status code. The implementation's approach (reusing error/http_status to match the other HTTP checks, per the code comments) seems more consistent with the rest of the codebase than what the description states — likely just a stale description, not a code issue.

  3. transportErrorKey (bandwidthChecker.go:271-281) correctly unwraps *net.OpError via errors.As (which also handles the *url.Error wrapper returned by client.Do), stripping the connection-specific address while keeping Op/Net/underlying error text. This is a sound way to keep the bucket count small across retries without losing the meaningful failure cause.

No security, concurrency, or correctness bugs found. I was unable to execute go build/go vet/go test myself in this session due to tool permission restrictions on non-git Bash commands — the PR description states these were run locally and passed, and the diff is consistent with that.
· branch fix/bandwidth-error-differentiation

…ks do

Every failure kind (request-build error, transport error, bad status
code, body-read error) previously collapsed into one generic error
count, so a failed run couldn't be diagnosed from the metric alone and
the chart never distinguished why a window failed.

Transport errors now report their actual (address-normalized) cause
under the same "error" key the other HTTP checks use, driving the same
"Failure" widget grouping. Status codes are now reported for every call,
successful or not, under "http_status", with "expected_http_status"
driving a new "Unexpected Status" grouping - mirroring the other checks'
per-request fields exactly, generalized to "did this window see any of
these" for the windowed bandwidth metric.
@joshiste
joshiste force-pushed the fix/bandwidth-error-differentiation branch from 0bacb07 to 9f6fc6e Compare August 6, 2026 10:58
@joshiste joshiste changed the title fix: differentiate transport errors and HTTP status codes in the bandwidth check metric fix: report bandwidth check failures the same way the other HTTP checks do Aug 6, 2026
@joshiste
joshiste enabled auto-merge (squash) August 6, 2026 11:03
@sonarqubecloud

sonarqubecloud Bot commented Aug 6, 2026

Copy link
Copy Markdown

@joshiste
joshiste merged commit 960166b into main Aug 6, 2026
13 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 6, 2026
@joshiste
joshiste deleted the fix/bandwidth-error-differentiation branch August 6, 2026 11:36
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant