use obzenflow_core::StageId;
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct CircuitBreakerMetrics {
pub requests_total: u64,
pub successes_total: u64,
pub failures_total: u64,
pub slow_total: u64,
pub rejections_total: u64,
pub opened_total: u64,
pub time_closed_seconds: f64,
pub time_open_seconds: f64,
pub time_half_open_seconds: f64,
pub state: CircuitBreakerState,
}
#[derive(Debug, Clone, Default)]
pub struct RateLimiterMetrics {
pub events_total: u64,
pub delayed_total: u64,
pub tokens_consumed_total: f64,
pub delay_seconds_total: f64,
pub bucket_tokens: f64,
pub bucket_capacity: f64,
}
pub mod cb_state {
pub const CLOSED: u8 = 0;
pub const OPEN: u8 = 1;
pub const HALF_OPEN: u8 = 2;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CircuitBreakerState {
#[default]
Closed,
Open,
HalfOpen,
}
impl CircuitBreakerState {
pub fn is_open(self) -> bool {
matches!(self, Self::Open)
}
pub fn from_u8(value: u8) -> Self {
match value {
cb_state::OPEN => Self::Open,
cb_state::HALF_OPEN => Self::HalfOpen,
_ => Self::Closed,
}
}
pub fn as_u8(self) -> u8 {
match self {
Self::Closed => cb_state::CLOSED,
Self::Open => cb_state::OPEN,
Self::HalfOpen => cb_state::HALF_OPEN,
}
}
pub fn stable_label(self) -> &'static str {
match self {
Self::Closed => "closed",
Self::Open => "open",
Self::HalfOpen => "half_open",
}
}
pub fn stable_gauge(self) -> f64 {
match self {
Self::Closed => 0.0,
Self::Open => 1.0,
Self::HalfOpen => 0.5,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CircuitBreakerStateSnapshot {
pub state: CircuitBreakerState,
pub generation: u64,
}
pub trait CircuitBreakerStateView: Send + Sync + std::fmt::Debug {
fn snapshot(&self) -> CircuitBreakerStateSnapshot;
fn is_open(&self) -> bool {
self.snapshot().state.is_open()
}
}
pub type CircuitBreakerSnapshotter = dyn Fn() -> Option<CircuitBreakerMetrics> + Send + Sync;
pub type RateLimiterSnapshotter = dyn Fn() -> Option<RateLimiterMetrics> + Send + Sync;
pub trait ControlPlaneProvider: Send + Sync {
fn circuit_breaker_snapshotter(
&self,
stage_id: &StageId,
) -> Option<Arc<CircuitBreakerSnapshotter>>;
fn rate_limiter_snapshotter(&self, stage_id: &StageId) -> Option<Arc<RateLimiterSnapshotter>>;
fn circuit_breaker_state_view(
&self,
_stage_id: &StageId,
) -> Option<Arc<dyn CircuitBreakerStateView>> {
None
}
fn effect_circuit_breaker_snapshotters(
&self,
_stage_id: &StageId,
) -> Vec<(String, Arc<CircuitBreakerSnapshotter>)> {
Vec::new()
}
fn effect_rate_limiter_snapshotters(
&self,
_stage_id: &StageId,
) -> Vec<(String, Arc<RateLimiterSnapshotter>)> {
Vec::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct NoControlPlane;
impl ControlPlaneProvider for NoControlPlane {
fn circuit_breaker_snapshotter(&self, _: &StageId) -> Option<Arc<CircuitBreakerSnapshotter>> {
None
}
fn rate_limiter_snapshotter(&self, _: &StageId) -> Option<Arc<RateLimiterSnapshotter>> {
None
}
}