fix(rustproxy-http): validate pooled HTTP/2 connections asynchronously before reuse and evict stale senders
This commit is contained in:
@@ -659,17 +659,40 @@ impl HttpProxyService {
|
||||
h2: use_h2,
|
||||
};
|
||||
|
||||
// H2 pool checkout (H2 senders are Clone and multiplexed)
|
||||
// H2 pool checkout with async readiness validation.
|
||||
// checkout_h2 does synchronous is_closed()/is_ready() checks, but these
|
||||
// reflect cached state — the H2 connection driver (a separate tokio task)
|
||||
// may not have processed a pending GOAWAY/RST yet. The ready().await
|
||||
// forces the runtime to yield, giving the driver a chance to detect failures.
|
||||
if use_h2 {
|
||||
if let Some(sender) = self.connection_pool.checkout_h2(&pool_key) {
|
||||
self.metrics.backend_pool_hit(&upstream_key);
|
||||
self.metrics.set_backend_protocol(&upstream_key, "h2");
|
||||
let result = self.forward_h2_pooled(
|
||||
sender, parts, body, upstream_headers, &upstream_path,
|
||||
route_match.route, route_id, &ip_str, &pool_key, domain_str, &conn_activity,
|
||||
).await;
|
||||
self.upstream_selector.connection_ended(&upstream_key);
|
||||
return result;
|
||||
if let Some((mut sender, age)) = self.connection_pool.checkout_h2(&pool_key) {
|
||||
match tokio::time::timeout(
|
||||
std::time::Duration::from_millis(500),
|
||||
sender.ready(),
|
||||
).await {
|
||||
Ok(Ok(())) => {
|
||||
self.metrics.backend_pool_hit(&upstream_key);
|
||||
self.metrics.set_backend_protocol(&upstream_key, "h2");
|
||||
let result = self.forward_h2_pooled(
|
||||
sender, parts, body, upstream_headers, &upstream_path,
|
||||
route_match.route, route_id, &ip_str, &pool_key, domain_str, &conn_activity,
|
||||
).await;
|
||||
self.upstream_selector.connection_ended(&upstream_key);
|
||||
return result;
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
warn!(backend = %upstream_key, age_secs = age.as_secs(),
|
||||
"Pooled H2 sender failed ready check (GOAWAY/RST): {}, evicting", e);
|
||||
self.connection_pool.remove_h2(&pool_key);
|
||||
// Fall through to fresh connection
|
||||
}
|
||||
Err(_) => {
|
||||
warn!(backend = %upstream_key, age_secs = age.as_secs(),
|
||||
"Pooled H2 sender ready check timed out (500ms), evicting");
|
||||
self.connection_pool.remove_h2(&pool_key);
|
||||
// Fall through to fresh connection
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user