Skip to main content

Mountain/IPC/Connection/
Health.rs

1//! # Health Checker (IPC Connection)
2//!
3//! ## RESPONSIBILITIES
4//! This module provides connection health checking functionality for the
5//! IPC layer. It monitors connection health through periodic checks and
6//! provides metrics for debugging and monitoring.
7//!
8//! ## ARCHITECTURAL ROLE
9//! This module is part of the monitoring subsystem in the connection management
10//! layer, providing health assessments for active connections.
11//!
12//! ## KEY COMPONENTS
13//!
14//! - **HealthChecker**: Periodic connection health monitoring
15//!
16//! ## ERROR HANDLING
17// Health checks return boolean results indicating health status.
18//
19// ## LOGGING
20// Debug-level logging for health check results.
21//
22// ## Performance Considerations
23// - Health checks run in background tasks
24// - Non-blocking implementation using Tokio
25// - Configurable check intervals
26// - Timeout-based health assessment
27//
28// ## TODO
29// - Add configurable health check strategies
30// - Implement health check customization
31// - Add health history tracking
32// - Support multiple health check types
33
34use super::Types::ConnectionHandle;
35use crate::dev_log;
36
37/// Connection health checker
38///
39/// This structure provides periodic health checking for connections,
40/// monitoring response times and overall connection health.
41///
42/// ## Health Check Process
43///
44/// ```text
45/// Connection
46///     |
47///     | 1. Send ping
48///     v
49/// Measure response time
50///     |
51///     | 2. Compare to timeout
52///     v
53/// Health decision (healthy/unhealthy)
54/// ```
55///
56/// ## Health Criteria
57///
58/// A connection is considered healthy if:
59/// - Response time < ping_timeout (default 5 seconds)
60///
61/// ## Example Usage
62///
63/// ```rust,ignore
64/// let checker = HealthChecker::new();
65/// let mut handle = ConnectionHandle::new();
66///
67/// let is_healthy = checker.check_connection_health(&mut handle).await;
68/// ```
69pub struct HealthChecker {
70	/// Maximum allowed response time for a connection to be considered healthy
71	ping_timeout:std::time::Duration,
72}
73
74impl HealthChecker {
75	/// Create a new health checker with default settings
76	///
77	/// Default ping timeout is 5 seconds.
78	pub fn new() -> Self {
79		dev_log!("ipc", "[HealthChecker] Creating health checker with 5s timeout");
80
81		Self { ping_timeout:std::time::Duration::from_secs(5) }
82	}
83
84	/// Create a new health checker with custom timeout
85	///
86	/// ## Parameters
87	/// - `ping_timeout`: Maximum allowed response time
88	pub fn with_timeout(ping_timeout:std::time::Duration) -> Self {
89		dev_log!("ipc", "[HealthChecker] Creating health checker with {:?} timeout", ping_timeout);
90
91		Self { ping_timeout }
92	}
93
94	/// Check connection health by sending a ping
95	///
96	/// This method simulates a health check by measuring response time.
97	/// In a production environment, this would send an actual ping message
98	/// through the connection.
99	///
100	/// ## Parameters
101	/// - `handle`: Mutable reference to the connection handle to update based
102	///   on health
103	///
104	/// ## Returns
105	/// - `true`: Connection is healthy
106	/// - `false`: Connection is unhealthy
107	///
108	/// ## Example
109	///
110	/// ```rust,ignore
111	/// let is_healthy = checker.check_connection_health(&mut handle).await;
112	/// ```
113	pub async fn check_connection_health(&self, handle:&mut ConnectionHandle) -> bool {
114		let start_time = std::time::Instant::now();
115
116		// Simulate network latency (in production, this would be an actual ping)
117		// Using a small delay to simulate realistic network conditions
118		tokio::time::sleep(std::time::Duration::from_millis(10)).await;
119
120		let response_time = start_time.elapsed();
121
122		// Connection is healthy if response time is within timeout
123		let is_healthy = response_time < self.ping_timeout;
124
125		if is_healthy {
126			dev_log!(
127				"ipc",
128				"[HealthChecker] Connection {} is healthy (response time: {:?})",
129				handle.id,
130				response_time
131			);
132		} else {
133			dev_log!(
134				"ipc",
135				"[HealthChecker] Connection {} is unhealthy (response time: {:?}, timeout: {:?})",
136				handle.id,
137				response_time,
138				self.ping_timeout
139			);
140		}
141
142		is_healthy
143	}
144
145	/// Get the ping timeout
146	pub fn ping_timeout(&self) -> std::time::Duration { self.ping_timeout }
147
148	/// Set a new ping timeout
149	pub fn set_ping_timeout(&mut self, timeout:std::time::Duration) {
150		self.ping_timeout = timeout;
151
152		dev_log!("ipc", "[HealthChecker] Ping timeout updated to {:?}", timeout);
153	}
154}
155
156impl Default for HealthChecker {
157	fn default() -> Self { Self::new() }
158}
159
160#[cfg(test)]
161mod tests {
162
163	use super::*;
164
165	#[tokio::test]
166	async fn test_health_checker_creation() {
167		let checker = HealthChecker::new();
168
169		assert_eq!(checker.ping_timeout, std::time::Duration::from_secs(5));
170	}
171
172	#[tokio::test]
173	async fn test_health_checker_custom_timeout() {
174		let timeout = std::time::Duration::from_secs(10);
175
176		let checker = HealthChecker::with_timeout(timeout);
177
178		assert_eq!(checker.ping_timeout, timeout);
179	}
180
181	#[tokio::test]
182	async fn test_check_connection_health_healthy() {
183		let checker = HealthChecker::new();
184
185		let mut handle = ConnectionHandle::new();
186
187		let is_healthy = checker.check_connection_health(&mut handle).await;
188
189		assert!(is_healthy);
190	}
191
192	#[tokio::test]
193	async fn test_check_connection_health_unhealthy() {
194		// Create a checker with very short timeout
195		let timeout = std::time::Duration::from_millis(1);
196
197		let checker = HealthChecker::with_timeout(timeout);
198
199		let mut handle = ConnectionHandle::new();
200
201		// The simulated latency (10ms) should exceed the timeout (1ms)
202		let is_healthy = checker.check_connection_health(&mut handle).await;
203
204		assert!(!is_healthy);
205	}
206
207	#[test]
208	fn test_default_health_checker() {
209		let checker = HealthChecker::default();
210
211		assert_eq!(checker.ping_timeout, std::time::Duration::from_secs(5));
212	}
213
214	#[test]
215	fn test_set_ping_timeout() {
216		let mut checker = HealthChecker::new();
217
218		assert_eq!(checker.ping_timeout, std::time::Duration::from_secs(5));
219
220		let new_timeout = std::time::Duration::from_secs(15);
221
222		checker.set_ping_timeout(new_timeout);
223
224		assert_eq!(checker.ping_timeout, new_timeout);
225	}
226}