pub mod config;
pub mod state;
pub mod breaker;
pub mod manager;
pub mod sliding_counter;
pub mod metrics;
pub mod adaptive;
pub mod agent;
pub use config::{
CircuitBreakerConfig, CircuitBreakerConfigBuilder, FailureConditions,
SyncModeThresholds, NodeOverride,
};
pub use state::{CircuitState, StateTransition, TransitionReason};
pub use breaker::{CircuitBreaker, CircuitOpen, RequestGuard};
pub use manager::{CircuitBreakerManager, ManagerConfig};
pub use sliding_counter::SlidingWindowCounter;
pub use metrics::{CircuitMetrics, CircuitStats, NodeCircuitStats};
pub use adaptive::{AdaptiveThreshold, RollingStats};
pub use agent::{AgentRetryStrategy, RetryDecision, ConversationFallback};
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[test]
fn test_circuit_breaker_basic() {
let config = CircuitBreakerConfig::builder()
.failure_threshold(3)
.failure_window_secs(60)
.cooldown_secs(5)
.build();
let breaker = CircuitBreaker::new("test-node", config);
assert_eq!(breaker.get_state(), CircuitState::Closed);
for _ in 0..3 {
breaker.record_failure_direct();
}
assert_eq!(breaker.get_state(), CircuitState::Open);
}
#[test]
fn test_circuit_state_transitions() {
let config = CircuitBreakerConfig::builder()
.failure_threshold(2)
.cooldown_secs(0) .half_open_success_threshold(2)
.build();
let breaker = CircuitBreaker::new("test-node", config);
breaker.record_failure_direct();
breaker.record_failure_direct();
assert_eq!(breaker.get_state(), CircuitState::Open);
std::thread::sleep(Duration::from_millis(50));
let guard = breaker.allow_request().expect("should allow request after cooldown");
assert_eq!(breaker.get_state(), CircuitState::HalfOpen);
guard.success();
let guard = breaker.allow_request().expect("should allow probe");
guard.success();
assert_eq!(breaker.get_state(), CircuitState::Closed);
}
#[test]
fn test_half_open_failure() {
let config = CircuitBreakerConfig::builder()
.failure_threshold(1)
.cooldown_secs(0)
.build();
let breaker = CircuitBreaker::new("test-node", config);
breaker.record_failure_direct();
std::thread::sleep(Duration::from_millis(50));
let guard = breaker.allow_request().expect("should allow after cooldown");
assert_eq!(breaker.get_state(), CircuitState::HalfOpen);
guard.failure("test failure");
assert_eq!(breaker.get_state(), CircuitState::Open);
}
}