You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
proxy: no request-outcome metric to distinguish routing (500) / upstream (502) / client-closed (499) failures #3757
The reverse proxy (packages/shared/pkg/proxy, used by both client-proxy and the orchestrator sandbox proxy) has no request-outcome metric. Its only metrics are connection gauges (*.proxy.server.connections.open, *.proxy.pool.connections.open, *.proxy.pool.size). There is no counter that distinguishes how a proxied request ended:
routing failure (destination could not be resolved) — answered 500
upstream unreachable (destination resolved, TCP to the node failed) — answered 502
client closed the connection before the server responded — surfaces as 499 in the gin layer, but the proxy data-plane has no equivalent counter
sandbox not found
too many incoming connections (connection-limit shed)
success
Motivation
This is the exact blind spot behind the 2026-10-17 node-churn incident: during a scale-down, sandboxes on removed nodes surfaced as Failed to route request to sandbox, and because routing failures (500) and upstream-unreachable failures (502) were indistinguishable at the metric layer, the only way to tell them apart was scraping logs. #3691 / #3692 split the message; this issue adds the metric so the split is visible on dashboards and alertable (e.g. a spike in upstream_unreachable by node = stale routing records pointing at a dead node).
Proposal
Add a request-outcome counter to the shared proxy, recorded at the points where a request's fate is decided:
the pool ErrorHandler (upstream_unreachable, client_closed, routing_failed)
ModifyResponse (ok)
Keep the shared proxy telemetry-agnostic: thread an OnRequestOutcome(ctx, outcome string) callback into reverseproxy.New (mirroring the existing ConnectionLimitConfig callbacks), and have each service own its counter + name:
Activity