use std::time::Duration;
#[derive(Debug, Clone, PartialEq)]
pub struct ResizerConfig {
pub lower_bound: usize,
pub upper_bound: usize,
pub pressure_threshold: f64,
pub backoff_threshold: f64,
pub rampup_rate: f64,
pub backoff_rate: f64,
pub messages_per_resize: u64,
pub backoff_delay: Duration,
}
impl Default for ResizerConfig {
fn default() -> Self {
Self {
lower_bound: 1,
upper_bound: 10,
pressure_threshold: 1.0,
backoff_threshold: 0.3,
rampup_rate: 0.2,
backoff_rate: 0.1,
messages_per_resize: 10,
backoff_delay: Duration::from_secs(10),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ResizeAdvice {
pub delta: i32,
}
impl ResizerConfig {
pub fn compute_delta(&self, current_size: usize, busy: usize) -> ResizeAdvice {
if current_size == 0 {
return ResizeAdvice { delta: self.lower_bound as i32 };
}
let load = busy as f64 / current_size as f64;
let target = if load >= self.pressure_threshold {
let grown = current_size as f64 * (1.0 + self.rampup_rate);
grown.ceil() as usize
} else if load <= self.backoff_threshold {
let shrunk = current_size as f64 * (1.0 - self.backoff_rate);
shrunk.floor() as usize
} else {
current_size
};
let clamped = target.clamp(self.lower_bound, self.upper_bound);
ResizeAdvice { delta: clamped as i32 - current_size as i32 }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_grows_under_pressure() {
let r = ResizerConfig::default();
let advice = r.compute_delta(2, 2);
assert!(advice.delta > 0, "expected growth, got {:?}", advice);
}
#[test]
fn default_shrinks_when_idle() {
let r = ResizerConfig { lower_bound: 1, upper_bound: 10, backoff_rate: 0.5, ..Default::default() };
let advice = r.compute_delta(8, 0);
assert!(advice.delta < 0, "expected shrink, got {:?}", advice);
}
#[test]
fn clamps_to_upper_bound() {
let r = ResizerConfig {
lower_bound: 1,
upper_bound: 4,
rampup_rate: 5.0,
pressure_threshold: 0.5,
..Default::default()
};
let advice = r.compute_delta(3, 3);
assert_eq!(advice.delta, 1);
}
#[test]
fn clamps_to_lower_bound() {
let r = ResizerConfig {
lower_bound: 2,
upper_bound: 10,
backoff_rate: 0.9,
backoff_threshold: 0.5,
..Default::default()
};
let advice = r.compute_delta(3, 0);
assert_eq!(advice.delta, -1);
}
#[test]
fn zero_size_grows_to_lower_bound() {
let r = ResizerConfig { lower_bound: 3, ..Default::default() };
let advice = r.compute_delta(0, 0);
assert_eq!(advice.delta, 3);
}
#[test]
fn no_change_when_load_in_band() {
let r = ResizerConfig { pressure_threshold: 0.9, backoff_threshold: 0.1, ..Default::default() };
let advice = r.compute_delta(5, 3);
assert_eq!(advice.delta, 0);
}
}