This commit is contained in:
Mateusz Gruszczyński committed 2026-10-05 10:58:50 +02:00
1 parent c819f0a335
commit e1a59f6e56
53 files changed
+817 -380

No files matched your search

+19 -1
View File
@@ -54,6 +54,16 @@ pub struct Keepalive {
pub idle_timeout_seconds: u64,
pub max_idle_per_host: usize,
pub tcp_keepalive_seconds: u64,
/// Rebuild a backend Hyper client after this many requests. The counter is
/// per backend/client generation, not per TCP connection. Zero disables
/// request-count based recycling.
pub pool_recycle_requests: u64,
/// Maximum age of one backend Hyper client generation. Zero disables
/// time-based recycling.
pub pool_recycle_seconds: u64,
/// Bound Hyper's adaptive HTTP/1 read buffer per connection. Hyper requires
/// at least 8192 bytes. This affects upstream HTTP/1 only.
pub http1_max_buffer_bytes: usize,
}
impl Default for Keepalive {
fn default() -> Self {
@@ -62,6 +72,9 @@ impl Default for Keepalive {
idle_timeout_seconds: 30,
max_idle_per_host: 4,
tcp_keepalive_seconds: 30,
pool_recycle_requests: 25_000,
pool_recycle_seconds: 3_600,
http1_max_buffer_bytes: 131_072,
}
}
}
@@ -255,7 +268,12 @@ impl Settings {
ensure!(
(1..=3600).contains(&k.idle_timeout_seconds)
&& (1..=3600).contains(&k.tcp_keepalive_seconds)
&& (1..=64).contains(&k.max_idle_per_host),
&& (1..=64).contains(&k.max_idle_per_host)
&& (k.pool_recycle_requests == 0
|| (1_000..=10_000_000).contains(&k.pool_recycle_requests))
&& (k.pool_recycle_seconds == 0
|| (60..=604_800).contains(&k.pool_recycle_seconds))
&& (8_192..=1_048_576).contains(&k.http1_max_buffer_bytes),
"invalid keepalive limits"
);
ensure!(
+17
View File
@@ -61,6 +61,23 @@ impl Pool {
"traffic_bytes_per_second".into(),
json!(m.state.traffic_rate()),
);
let client_rotation = m.backend.client.rotation_stats();
item.insert(
"upstream_client_generation".into(),
json!(client_rotation.generation),
);
item.insert(
"upstream_client_generation_requests".into(),
json!(client_rotation.generation_requests),
);
item.insert(
"upstream_client_generation_age_seconds".into(),
json!(client_rotation.generation_age_seconds),
);
item.insert(
"upstream_client_rotations_total".into(),
json!(client_rotation.rotations),
);
item.insert("latency_ms".into(), json!(h.latency_us as f64 / 1000.0));
item.insert("ewma_latency_ms".into(), json!(h.ewma_us as f64 / 1000.0));
item.insert("last_probe_ms".into(), json!(h.last_probe_ms));
+24
View File
@@ -72,6 +72,30 @@ fn legacy_settings_without_passive_health_default_to_off() {
assert!(parsed.retry.retry_connect_errors);
assert!(parsed.retry.retry_timeouts);
assert_eq!(parsed.retry.retry_statuses, vec![502, 503, 504]);
assert_eq!(parsed.keepalive.pool_recycle_requests, 25_000);
assert_eq!(parsed.keepalive.pool_recycle_seconds, 3_600);
assert_eq!(parsed.keepalive.http1_max_buffer_bytes, 131_072);
}
#[test]
fn upstream_pool_recycle_limits_are_bounded_and_can_be_disabled() {
let mut settings = Settings::default();
assert!(settings.validate().is_ok());
settings.keepalive.pool_recycle_requests = 0;
settings.keepalive.pool_recycle_seconds = 0;
assert!(settings.validate().is_ok());
settings.keepalive.pool_recycle_requests = 999;
assert!(settings.validate().is_err());
settings.keepalive.pool_recycle_requests = 1_000;
settings.keepalive.pool_recycle_seconds = 59;
assert!(settings.validate().is_err());
settings.keepalive.pool_recycle_seconds = 60;
settings.keepalive.http1_max_buffer_bytes = 8_191;
assert!(settings.validate().is_err());
settings.keepalive.http1_max_buffer_bytes = 8_192;
assert!(settings.validate().is_ok());
}
#[test]