Avoid WebSocket connection waits in Guardian v2 classification (#43408)

## Why

When no healthy pooled WebSocket is available, classification waits for a new connection to open and can stall on its handshake.

## What changed

- Use HTTP streaming when no healthy idle WebSocket is ready, and replenish the pool in the background with a five-minute cooldown after connection timeouts.
- Share concurrency limits and the sampling retry budget across both transports, and bound the wait for HTTP response headers.
- Cancel superseded requests while awaiting response headers and stop SSE polling when the consumer closes.

## Testing

Add coverage for HTTP fallback and recovery after cooldown, shared transport capacity, stalled response headers, and cancellation before headers or during body draining. Update sampler and extension tests to cover fallback after socket expiry, authentication changes, and transient failures.

GitOrigin-RevId: 0b23ccc1bfb2dfdbc8d2791d097706cd4dd44f39
This commit is contained in:
jif
2026-09-07 09:24:03 +00:00
committed by copyberry
parent 5ecb3afd1b
commit 7769bccbb2
8 changed files with 1002 additions and 473 deletions
+5 -1
View File
@@ -578,7 +578,11 @@ async fn process_sse_with_treatment(
loop {
let start = Instant::now();
let response = timeout(idle_timeout, stream.next()).await;
let response = tokio::select! {
biased;
_ = tx_event.closed() => return,
response = timeout(idle_timeout, stream.next()) => response,
};
if let Some(t) = telemetry.as_ref() {
t.on_sse_poll(&response, start.elapsed());
}