Skip to main content

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#[cfg_attr(feature = "ts-bindings", derive(ts_rs::TS), ts(export))]
13#[serde(tag = "status", rename_all = "lowercase")]
14pub enum ServerHealthStatus {
15    /// Server is responding to health checks and process is alive.
16    Healthy,
17
18    /// Server is running but experiencing issues.
19    ///
20    /// Example: HTTP health endpoint returns non-200 status.
21    Degraded {
22        /// Human-readable reason for degraded state.
23        reason: String,
24    },
25
26    /// Server process is alive but HTTP endpoint is unreachable.
27    ///
28    /// Example: Connection timeout or refused.
29    Unreachable {
30        /// Last error message from health check attempt.
31        #[serde(rename = "lastError")]
32        last_error: String,
33    },
34
35    /// Server process has died unexpectedly.
36    ///
37    /// Detected via PID check (process no longer exists).
38    ProcessDied,
39}
40
41impl ServerHealthStatus {
42    /// Check if the status represents a failed/critical state.
43    #[must_use]
44    pub const fn is_failed(&self) -> bool {
45        matches!(self, Self::ProcessDied | Self::Unreachable { .. })
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn test_health_status_classification() {
55        assert!(!ServerHealthStatus::Healthy.is_failed());
56
57        let degraded = ServerHealthStatus::Degraded {
58            reason: "slow response".to_string(),
59        };
60        assert!(!degraded.is_failed());
61
62        let unreachable = ServerHealthStatus::Unreachable {
63            last_error: "connection refused".to_string(),
64        };
65        assert!(unreachable.is_failed());
66
67        assert!(ServerHealthStatus::ProcessDied.is_failed());
68    }
69
70    #[test]
71    fn test_serialization() {
72        let status = ServerHealthStatus::Degraded {
73            reason: "high latency".to_string(),
74        };
75        let json = serde_json::to_string(&status).unwrap();
76        assert!(json.contains("\"status\":\"degraded\""));
77        assert!(json.contains("\"reason\":\"high latency\""));
78    }
79}