From 43f0fa90fc1bd8a60c4c32dd5b437b2f74a6fba0 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 22 Feb 2026 22:41:07 +0100 Subject: [PATCH] feat(common): add CircuitBreakerTrait for shared circuit breaker interface Define an async trait that abstracts the circuit breaker state machine (Closed -> Open -> HalfOpen) so different implementations can be used polymorphically. Implement the trait for the existing tokio::Mutex-based CircuitBreaker struct by delegating to its existing async methods. Co-Authored-By: Claude Opus 4.6 --- common/src/resilience/circuit_breaker.rs | 47 ++++++++++++++++++++++++ common/src/resilience/mod.rs | 4 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/common/src/resilience/circuit_breaker.rs b/common/src/resilience/circuit_breaker.rs index a9b3465ed..785d8de39 100644 --- a/common/src/resilience/circuit_breaker.rs +++ b/common/src/resilience/circuit_breaker.rs @@ -47,6 +47,30 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::sync::Mutex; +/// Core circuit breaker trait for the state machine pattern. +/// +/// Implementors manage the Closed -> Open -> HalfOpen state transitions. +/// This trait provides a common interface so different circuit breaker +/// implementations (e.g., tokio-based, parking_lot-based) can be used +/// polymorphically. +#[async_trait::async_trait] +pub trait CircuitBreakerTrait: Send + Sync { + /// Check if a request is allowed through. + async fn can_execute(&self) -> bool; + + /// Record a successful operation. + async fn record_success(&self); + + /// Record a failed operation. + async fn record_failure(&self); + + /// Get current state. + async fn state(&self) -> CircuitBreakerState; + + /// Reset to closed state. + async fn reset(&self); +} + /// Circuit breaker states #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum CircuitBreakerState { @@ -397,3 +421,26 @@ impl std::fmt::Debug for CircuitBreaker { .finish() } } + +#[async_trait::async_trait] +impl CircuitBreakerTrait for CircuitBreaker { + async fn can_execute(&self) -> bool { + CircuitBreaker::can_execute(self).await + } + + async fn record_success(&self) { + CircuitBreaker::record_success(self).await; + } + + async fn record_failure(&self) { + CircuitBreaker::record_failure(self).await; + } + + async fn state(&self) -> CircuitBreakerState { + CircuitBreaker::state(self).await + } + + async fn reset(&self) { + CircuitBreaker::reset(self).await; + } +} diff --git a/common/src/resilience/mod.rs b/common/src/resilience/mod.rs index 7654d5a85..a9be6c062 100644 --- a/common/src/resilience/mod.rs +++ b/common/src/resilience/mod.rs @@ -61,5 +61,7 @@ mod tests; // Re-export commonly used types pub use bounded_concurrency::{BoundedExecutor, BoundedExecutorError}; -pub use circuit_breaker::{CircuitBreaker, CircuitBreakerConfig, CircuitBreakerState}; +pub use circuit_breaker::{ + CircuitBreaker, CircuitBreakerConfig, CircuitBreakerState, CircuitBreakerTrait, +}; pub use retry::{retry_with_backoff, RetryConfig, RetryContext, RetryError};