#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum BackpressureLevel {
Normal = 0,
Warn = 1,
Throttle = 2,
Critical = 3,
Emergency = 4,
Shutdown = 5,
}
impl BackpressureLevel {
#[must_use]
pub fn from_pressure(pressure: f64) -> Self {
match pressure {
p if p < 0.70 => Self::Normal,
p if p < 0.80 => Self::Warn,
p if p < 0.90 => Self::Throttle,
p if p < 0.95 => Self::Critical,
p if p < 0.98 => Self::Emergency,
_ => Self::Shutdown,
}
}
#[must_use]
pub fn should_accept_writes(&self) -> bool {
matches!(self, Self::Normal | Self::Warn | Self::Throttle)
}
#[must_use]
pub fn should_accept_reads(&self) -> bool {
!matches!(self, Self::Shutdown)
}
#[must_use]
pub fn eviction_multiplier(&self) -> f64 {
match self {
Self::Normal => 1.0,
Self::Warn => 1.5,
Self::Throttle => 2.0,
Self::Critical => 3.0,
Self::Emergency => 5.0,
Self::Shutdown => 10.0,
}
}
#[must_use]
pub fn http_status_code(&self) -> Option<u16> {
match self {
Self::Normal | Self::Warn => None,
Self::Throttle => Some(429),
Self::Critical | Self::Emergency | Self::Shutdown => Some(503),
}
}
pub fn retry_after_secs(&self) -> Option<u64> {
match self {
Self::Throttle => Some(1),
Self::Critical => Some(5),
Self::Emergency | Self::Shutdown => Some(30),
_ => None,
}
}
pub fn description(&self) -> &'static str {
match self {
Self::Normal => "Normal operation",
Self::Warn => "Warning - high memory usage",
Self::Throttle => "Throttling - rate limiting active",
Self::Critical => "Critical - writes rejected",
Self::Emergency => "Emergency - read-only mode",
Self::Shutdown => "Shutdown - graceful shutdown initiated",
}
}
}
impl std::fmt::Display for BackpressureLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pressure_level_thresholds() {
assert_eq!(BackpressureLevel::from_pressure(0.0), BackpressureLevel::Normal);
assert_eq!(BackpressureLevel::from_pressure(0.69), BackpressureLevel::Normal);
assert_eq!(BackpressureLevel::from_pressure(0.70), BackpressureLevel::Warn);
assert_eq!(BackpressureLevel::from_pressure(0.79), BackpressureLevel::Warn);
assert_eq!(BackpressureLevel::from_pressure(0.80), BackpressureLevel::Throttle);
assert_eq!(BackpressureLevel::from_pressure(0.89), BackpressureLevel::Throttle);
assert_eq!(BackpressureLevel::from_pressure(0.90), BackpressureLevel::Critical);
assert_eq!(BackpressureLevel::from_pressure(0.94), BackpressureLevel::Critical);
assert_eq!(BackpressureLevel::from_pressure(0.95), BackpressureLevel::Emergency);
assert_eq!(BackpressureLevel::from_pressure(0.97), BackpressureLevel::Emergency);
assert_eq!(BackpressureLevel::from_pressure(0.98), BackpressureLevel::Shutdown);
assert_eq!(BackpressureLevel::from_pressure(1.0), BackpressureLevel::Shutdown);
}
#[test]
fn test_should_accept_writes() {
assert!(BackpressureLevel::Normal.should_accept_writes());
assert!(BackpressureLevel::Warn.should_accept_writes());
assert!(BackpressureLevel::Throttle.should_accept_writes());
assert!(!BackpressureLevel::Critical.should_accept_writes());
assert!(!BackpressureLevel::Emergency.should_accept_writes());
assert!(!BackpressureLevel::Shutdown.should_accept_writes());
}
#[test]
fn test_should_accept_reads() {
assert!(BackpressureLevel::Normal.should_accept_reads());
assert!(BackpressureLevel::Warn.should_accept_reads());
assert!(BackpressureLevel::Throttle.should_accept_reads());
assert!(BackpressureLevel::Critical.should_accept_reads());
assert!(BackpressureLevel::Emergency.should_accept_reads());
assert!(!BackpressureLevel::Shutdown.should_accept_reads());
}
#[test]
fn test_eviction_multiplier_increases_with_pressure() {
let levels = [
BackpressureLevel::Normal,
BackpressureLevel::Warn,
BackpressureLevel::Throttle,
BackpressureLevel::Critical,
BackpressureLevel::Emergency,
BackpressureLevel::Shutdown,
];
for i in 1..levels.len() {
assert!(
levels[i].eviction_multiplier() >= levels[i - 1].eviction_multiplier(),
"eviction multiplier should increase with pressure"
);
}
}
#[test]
fn test_http_status_codes() {
assert_eq!(BackpressureLevel::Normal.http_status_code(), None);
assert_eq!(BackpressureLevel::Warn.http_status_code(), None);
assert_eq!(BackpressureLevel::Throttle.http_status_code(), Some(429));
assert_eq!(BackpressureLevel::Critical.http_status_code(), Some(503));
assert_eq!(BackpressureLevel::Emergency.http_status_code(), Some(503));
assert_eq!(BackpressureLevel::Shutdown.http_status_code(), Some(503));
}
#[test]
fn test_retry_after_increases_with_severity() {
assert_eq!(BackpressureLevel::Normal.retry_after_secs(), None);
assert_eq!(BackpressureLevel::Throttle.retry_after_secs(), Some(1));
assert_eq!(BackpressureLevel::Critical.retry_after_secs(), Some(5));
assert_eq!(BackpressureLevel::Emergency.retry_after_secs(), Some(30));
}
#[test]
fn test_level_ordering() {
assert!(BackpressureLevel::Normal < BackpressureLevel::Warn);
assert!(BackpressureLevel::Warn < BackpressureLevel::Throttle);
assert!(BackpressureLevel::Throttle < BackpressureLevel::Critical);
assert!(BackpressureLevel::Critical < BackpressureLevel::Emergency);
assert!(BackpressureLevel::Emergency < BackpressureLevel::Shutdown);
}
}