use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum QueueDepthTier {
#[default]
Unknown = 0,
Normal = 1,
Warning = 2,
Critical = 3,
Overflow = 4,
}
impl PartialOrd for QueueDepthTier {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for QueueDepthTier {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(*self as u8).cmp(&(*other as u8))
}
}
impl QueueDepthTier {
#[must_use]
pub const fn is_evaluated(&self) -> bool {
!matches!(self, Self::Unknown)
}
#[must_use]
pub const fn is_warning(&self) -> bool {
matches!(self, Self::Warning | Self::Critical | Self::Overflow)
}
#[must_use]
pub const fn is_critical(&self) -> bool {
matches!(self, Self::Critical | Self::Overflow)
}
#[must_use]
pub const fn is_overflow(&self) -> bool {
matches!(self, Self::Overflow)
}
}
#[derive(Debug, Clone, Default)]
pub struct QueueDepthStatus {
pub tier: QueueDepthTier,
pub max_depth: i64,
pub worst_queue: String,
pub queue_depths: HashMap<String, i64>,
}
#[derive(Debug, Clone)]
pub struct ChannelHealthStatus {
pub evaluated: bool,
pub command_saturation_percent: f64,
pub command_available_capacity: usize,
pub command_messages_sent: u64,
pub command_overflow_events: u64,
pub is_saturated: bool,
pub is_critical: bool,
}
impl Default for ChannelHealthStatus {
fn default() -> Self {
Self {
evaluated: false, command_saturation_percent: 0.0,
command_available_capacity: 0,
command_messages_sent: 0,
command_overflow_events: 0,
is_saturated: false,
is_critical: false,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct DatabaseHealthStatus {
pub evaluated: bool,
pub is_connected: bool,
pub circuit_breaker_open: bool,
pub circuit_breaker_failures: u32,
pub last_check_duration_ms: u64,
pub error_message: Option<String>,
}
#[derive(Debug, Clone)]
pub enum BackpressureSource {
CircuitBreaker,
ChannelSaturation {
channel: String,
saturation_percent: f64,
},
QueueDepth {
queue: String,
depth: i64,
tier: QueueDepthTier,
},
}
#[derive(Debug, Clone, Default)]
pub struct BackpressureStatus {
pub active: bool,
pub reason: Option<String>,
pub retry_after_secs: Option<u64>,
pub source: Option<BackpressureSource>,
}
#[derive(Debug, Clone)]
pub struct BackpressureMetrics {
pub circuit_breaker_open: bool,
pub circuit_breaker_failures: u32,
pub command_channel_saturation_percent: f64,
pub command_channel_available_capacity: usize,
pub command_channel_messages_sent: u64,
pub command_channel_overflow_events: u64,
pub backpressure_active: bool,
pub queue_depth_tier: String,
pub queue_depth_max: i64,
pub queue_depth_worst_queue: String,
pub queue_depths: HashMap<String, i64>,
}
impl Default for BackpressureMetrics {
fn default() -> Self {
Self {
circuit_breaker_open: false,
circuit_breaker_failures: 0,
command_channel_saturation_percent: 0.0,
command_channel_available_capacity: 0,
command_channel_messages_sent: 0,
command_channel_overflow_events: 0,
backpressure_active: false,
queue_depth_tier: "Normal".to_string(),
queue_depth_max: 0,
queue_depth_worst_queue: String::new(),
queue_depths: HashMap::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct HealthConfig {
pub evaluation_interval_ms: u64,
pub check_database: bool,
pub check_channels: bool,
pub check_queues: bool,
pub stale_threshold_ms: u64,
pub database: DatabaseHealthConfig,
pub channels: ChannelHealthConfig,
pub queues: QueueHealthConfig,
}
impl Default for HealthConfig {
fn default() -> Self {
Self {
evaluation_interval_ms: 5000, check_database: true,
check_channels: true,
check_queues: true,
stale_threshold_ms: 30000, database: DatabaseHealthConfig::default(),
channels: ChannelHealthConfig::default(),
queues: QueueHealthConfig::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct DatabaseHealthConfig {
pub query_timeout_ms: u64,
}
impl Default for DatabaseHealthConfig {
fn default() -> Self {
Self {
query_timeout_ms: 1000,
}
}
}
#[derive(Debug, Clone)]
pub struct ChannelHealthConfig {
pub warning_threshold: f64,
pub critical_threshold: f64,
pub emergency_threshold: f64,
}
impl Default for ChannelHealthConfig {
fn default() -> Self {
Self {
warning_threshold: 70.0,
critical_threshold: 80.0,
emergency_threshold: 95.0,
}
}
}
#[derive(Debug, Clone)]
pub struct QueueHealthConfig {
pub warning_threshold: i64,
pub critical_threshold: i64,
pub overflow_threshold: i64,
}
impl Default for QueueHealthConfig {
fn default() -> Self {
Self {
warning_threshold: 1000,
critical_threshold: 5000,
overflow_threshold: 10000,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_queue_depth_tier_ordering() {
assert!(QueueDepthTier::Unknown < QueueDepthTier::Normal);
assert!(QueueDepthTier::Normal < QueueDepthTier::Warning);
assert!(QueueDepthTier::Warning < QueueDepthTier::Critical);
assert!(QueueDepthTier::Critical < QueueDepthTier::Overflow);
}
#[test]
fn test_queue_depth_tier_default() {
assert_eq!(QueueDepthTier::default(), QueueDepthTier::Unknown);
}
#[test]
fn test_backpressure_status_default() {
let status = BackpressureStatus::default();
assert!(!status.active);
assert!(status.reason.is_none());
assert!(status.retry_after_secs.is_none());
assert!(status.source.is_none());
}
#[test]
fn test_health_config_default() {
let config = HealthConfig::default();
assert_eq!(config.evaluation_interval_ms, 5000);
assert!(config.check_database);
assert!(config.check_channels);
assert!(config.check_queues);
assert_eq!(config.channels.critical_threshold, 80.0);
}
#[test]
fn test_database_health_status_default_is_unknown() {
let status = DatabaseHealthStatus::default();
assert!(!status.evaluated);
assert!(!status.is_connected);
assert!(!status.circuit_breaker_open);
}
#[test]
fn test_channel_health_status_default_is_unknown() {
let status = ChannelHealthStatus::default();
assert!(!status.evaluated);
assert!(!status.is_saturated);
assert!(!status.is_critical);
}
#[test]
fn test_queue_depth_status_default_is_unknown() {
let status = QueueDepthStatus::default();
assert_eq!(status.tier, QueueDepthTier::Unknown);
}
}