rustkernel_core/resilience/
mod.rs1pub mod circuit_breaker;
28pub mod health;
29pub mod recovery;
30pub mod timeout;
31
32pub use circuit_breaker::{CircuitBreaker, CircuitBreakerConfig, CircuitState};
33pub use health::{HealthCheck, HealthCheckResult, HealthProbe};
34pub use recovery::{RecoveryPolicy, RecoveryStrategy, RetryConfig};
35pub use timeout::{DeadlineContext, TimeoutConfig, TimeoutError};
36
37pub use ringkernel_core::health as ring_health;
39pub use ringkernel_core::rate_limiting as ring_rate_limiting;
40pub use ringkernel_core::timeout as ring_timeout;
41
42use serde::{Deserialize, Serialize};
43use std::time::Duration;
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct ResilienceConfig {
48 pub circuit_breaker: Option<CircuitBreakerConfig>,
50 pub timeout: Option<TimeoutConfig>,
52 pub recovery: Option<RecoveryPolicy>,
54 pub health_check_interval: Duration,
56}
57
58impl Default for ResilienceConfig {
59 fn default() -> Self {
60 Self {
61 circuit_breaker: Some(CircuitBreakerConfig::default()),
62 timeout: Some(TimeoutConfig::default()),
63 recovery: Some(RecoveryPolicy::default()),
64 health_check_interval: Duration::from_secs(10),
65 }
66 }
67}
68
69impl ResilienceConfig {
70 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn disabled() -> Self {
77 Self {
78 circuit_breaker: None,
79 timeout: None,
80 recovery: None,
81 health_check_interval: Duration::from_secs(60),
82 }
83 }
84
85 pub fn production() -> Self {
87 Self {
88 circuit_breaker: Some(CircuitBreakerConfig::production()),
89 timeout: Some(TimeoutConfig::production()),
90 recovery: Some(RecoveryPolicy::production()),
91 health_check_interval: Duration::from_secs(10),
92 }
93 }
94
95 pub fn development() -> Self {
97 Self {
98 circuit_breaker: Some(CircuitBreakerConfig::default()),
99 timeout: Some(TimeoutConfig::development()),
100 recovery: Some(RecoveryPolicy::development()),
101 health_check_interval: Duration::from_secs(30),
102 }
103 }
104
105 pub fn with_circuit_breaker(mut self, config: CircuitBreakerConfig) -> Self {
107 self.circuit_breaker = Some(config);
108 self
109 }
110
111 pub fn with_timeout(mut self, config: TimeoutConfig) -> Self {
113 self.timeout = Some(config);
114 self
115 }
116
117 pub fn with_recovery(mut self, policy: RecoveryPolicy) -> Self {
119 self.recovery = Some(policy);
120 self
121 }
122
123 pub fn with_health_check_interval(mut self, interval: Duration) -> Self {
125 self.health_check_interval = interval;
126 self
127 }
128}
129
130pub type ResilienceResult<T> = std::result::Result<T, ResilienceError>;
132
133#[derive(Debug, thiserror::Error)]
135pub enum ResilienceError {
136 #[error("Circuit breaker is open for {kernel_id}")]
138 CircuitOpen {
139 kernel_id: String,
141 },
142
143 #[error("Request timed out after {timeout:?}")]
145 Timeout {
146 timeout: Duration,
148 },
149
150 #[error("Deadline exceeded")]
152 DeadlineExceeded,
153
154 #[error("Max retries ({retries}) exceeded")]
156 MaxRetriesExceeded {
157 retries: u32,
159 },
160
161 #[error("Health check failed: {reason}")]
163 HealthCheckFailed {
164 reason: String,
166 },
167
168 #[error("Kernel error: {0}")]
170 KernelError(#[from] crate::error::KernelError),
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_default_config() {
179 let config = ResilienceConfig::default();
180 assert!(config.circuit_breaker.is_some());
181 assert!(config.timeout.is_some());
182 assert!(config.recovery.is_some());
183 }
184
185 #[test]
186 fn test_disabled_config() {
187 let config = ResilienceConfig::disabled();
188 assert!(config.circuit_breaker.is_none());
189 assert!(config.timeout.is_none());
190 assert!(config.recovery.is_none());
191 }
192
193 #[test]
194 fn test_production_config() {
195 let config = ResilienceConfig::production();
196 assert!(config.circuit_breaker.is_some());
197 assert!(config.timeout.is_some());
198 }
199}