gglib_core/ports/
server_health.rs

1//! Server health status types for monitoring.
2//!
3//! These types define the health states that a server process can be in,
4//! used for continuous monitoring after initial startup.
5
6use serde::{Deserialize, Serialize};
7
8/// Health status of a running server process.
9///
10/// Used by monitoring systems to track server state and emit lifecycle events.
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(tag = "status", rename_all = "lowercase")]
13pub enum ServerHealthStatus {
14    /// Server is responding to health checks and process is alive.
15    Healthy,
16
17    /// Server is running but experiencing issues.
18    ///
19    /// Example: HTTP health endpoint returns non-200 status.
20    Degraded {
21        /// Human-readable reason for degraded state.
22        reason: String,
23    },
24
25    /// Server process is alive but HTTP endpoint is unreachable.
26    ///
27    /// Example: Connection timeout or refused.
28    Unreachable {
29        /// Last error message from health check attempt.
30        #[serde(rename = "lastError")]
31        last_error: String,
32    },
33
34    /// Server process has died unexpectedly.
35    ///
36    /// Detected via PID check (process no longer exists).
37    ProcessDied,
38}
39
40impl ServerHealthStatus {
41    /// Check if the status represents a healthy state.
42    #[must_use]
43    pub const fn is_healthy(&self) -> bool {
44        matches!(self, Self::Healthy)
45    }
46
47    /// Check if the status represents a failed/critical state.
48    #[must_use]
49    pub const fn is_failed(&self) -> bool {
50        matches!(self, Self::ProcessDied | Self::Unreachable { .. })
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_health_status_classification() {
60        assert!(ServerHealthStatus::Healthy.is_healthy());
61        assert!(!ServerHealthStatus::Healthy.is_failed());
62
63        let degraded = ServerHealthStatus::Degraded {
64            reason: "slow response".to_string(),
65        };
66        assert!(!degraded.is_healthy());
67        assert!(!degraded.is_failed());
68
69        let unreachable = ServerHealthStatus::Unreachable {
70            last_error: "connection refused".to_string(),
71        };
72        assert!(!unreachable.is_healthy());
73        assert!(unreachable.is_failed());
74
75        assert!(!ServerHealthStatus::ProcessDied.is_healthy());
76        assert!(ServerHealthStatus::ProcessDied.is_failed());
77    }
78
79    #[test]
80    fn test_serialization() {
81        let status = ServerHealthStatus::Degraded {
82            reason: "high latency".to_string(),
83        };
84        let json = serde_json::to_string(&status).unwrap();
85        assert!(json.contains("\"status\":\"degraded\""));
86        assert!(json.contains("\"reason\":\"high latency\""));
87    }
88}