use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CircuitState {
Closed,
Open,
HalfOpen,
}
impl std::fmt::Display for CircuitState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CircuitState::Closed => write!(f, "closed"),
CircuitState::Open => write!(f, "open"),
CircuitState::HalfOpen => write!(f, "half-open"),
}
}
}
#[derive(Debug, Clone)]
pub struct CircuitBreakerConfig {
pub failure_threshold: u32,
pub success_threshold: u32,
pub open_duration: Duration,
pub failure_window: Duration,
}
impl Default for CircuitBreakerConfig {
fn default() -> Self {
Self {
failure_threshold: 5,
success_threshold: 2,
open_duration: Duration::from_secs(30),
failure_window: Duration::from_secs(60),
}
}
}
impl CircuitBreakerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_failure_threshold(mut self, threshold: u32) -> Self {
self.failure_threshold = threshold;
self
}
pub fn with_success_threshold(mut self, threshold: u32) -> Self {
self.success_threshold = threshold;
self
}
pub fn with_open_duration(mut self, duration: Duration) -> Self {
self.open_duration = duration;
self
}
pub fn with_failure_window(mut self, window: Duration) -> Self {
self.failure_window = window;
self
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CircuitBreakerStats {
pub state: String,
pub total_requests: u64,
pub successful_requests: u64,
pub failed_requests: u64,
pub rejected_requests: u64,
pub times_opened: u64,
pub consecutive_failures: u32,
pub consecutive_successes: u32,
}
impl CircuitBreakerStats {
pub fn success_rate(&self) -> f64 {
if self.total_requests == 0 {
1.0
} else {
self.successful_requests as f64 / self.total_requests as f64
}
}
}
pub trait CircuitBreaker: Send + Sync {
fn state(&self) -> CircuitState;
fn config(&self) -> &CircuitBreakerConfig;
fn stats(&self) -> CircuitBreakerStats;
fn record_success(&mut self);
fn record_failure(&mut self);
fn is_allowed(&self) -> bool;
fn reset(&mut self);
}