use std::time::Duration;
#[derive(Clone, Debug)]
pub struct CircuitBreaker {
pub window: Duration,
pub trip_threshold: f64,
pub min_requests: u32,
pub reset_after: Duration,
pub half_open_probes: u32,
pub failure_codes: Vec<tonic::Code>,
}
impl Default for CircuitBreaker {
fn default() -> Self {
Self {
window: Duration::from_secs(10),
trip_threshold: 0.5,
min_requests: 20,
reset_after: Duration::from_secs(30),
half_open_probes: 3,
failure_codes: vec![tonic::Code::Unavailable, tonic::Code::DeadlineExceeded],
}
}
}
impl CircuitBreaker {
pub fn aggressive() -> Self {
Self {
window: Duration::from_secs(5),
trip_threshold: 0.3,
min_requests: 5,
reset_after: Duration::from_secs(15),
half_open_probes: 1,
failure_codes: vec![tonic::Code::Unavailable, tonic::Code::DeadlineExceeded],
}
}
pub fn conservative() -> Self {
Self {
window: Duration::from_secs(30),
trip_threshold: 0.75,
min_requests: 50,
reset_after: Duration::from_secs(60),
half_open_probes: 5,
failure_codes: vec![tonic::Code::Unavailable],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_trip_threshold_is_half() {
let cb = CircuitBreaker::default();
assert!((cb.trip_threshold - 0.5).abs() < f64::EPSILON);
}
#[test]
fn aggressive_trips_faster_than_conservative() {
assert!(
CircuitBreaker::aggressive().min_requests < CircuitBreaker::conservative().min_requests
);
assert!(
CircuitBreaker::aggressive().trip_threshold
< CircuitBreaker::conservative().trip_threshold
);
}
}