Skip to main content

camel_api/
lifecycle.rs

1use crate::{CamelError, MetricsCollector};
2use async_trait::async_trait;
3use serde::{Deserialize, Serialize};
4use std::sync::Arc;
5
6/// Status of a Lifecycle service.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8pub enum ServiceStatus {
9    Stopped,
10    Started,
11    Failed,
12}
13
14/// Aggregated system health status.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16pub enum HealthStatus {
17    Healthy,
18    Unhealthy,
19}
20
21/// Lifecycle trait for background services.
22///
23/// This trait follows Apache Camel's Service pattern but uses a different name
24/// to avoid confusion with tower::Service which is the core of rust-camel's
25/// request processing.
26///
27/// # Why `&mut self`?
28///
29/// The `start()` and `stop()` methods require `&mut self` to ensure:
30/// - **Exclusive access**: Prevents concurrent start/stop operations on the same service
31/// - **Safe state transitions**: Services can safely mutate their internal state
32/// - **No data races**: Compile-time guarantee of single-threaded access to service state
33///
34/// This design choice trades flexibility for safety - services cannot be started/stopped
35/// concurrently, which simplifies implementation and prevents race conditions.
36#[async_trait]
37pub trait Lifecycle: Send + Sync {
38    /// Service name for logging
39    fn name(&self) -> &str;
40
41    /// Start service (called during CamelContext.start())
42    async fn start(&mut self) -> Result<(), CamelError>;
43
44    /// Stop service (called during CamelContext.stop())
45    async fn stop(&mut self) -> Result<(), CamelError>;
46
47    /// Optional: expose MetricsCollector for auto-registration
48    fn as_metrics_collector(&self) -> Option<Arc<dyn MetricsCollector>> {
49        None
50    }
51
52    /// Current status of the service.
53    fn status(&self) -> ServiceStatus {
54        ServiceStatus::Stopped
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    struct TestService;
63
64    #[async_trait]
65    impl Lifecycle for TestService {
66        fn name(&self) -> &str {
67            "test"
68        }
69
70        async fn start(&mut self) -> Result<(), CamelError> {
71            Ok(())
72        }
73
74        async fn stop(&mut self) -> Result<(), CamelError> {
75            Ok(())
76        }
77    }
78
79    #[tokio::test]
80    async fn test_lifecycle_trait() {
81        let mut service = TestService;
82        assert_eq!(service.name(), "test");
83        service.start().await.unwrap();
84        service.stop().await.unwrap();
85    }
86
87    #[test]
88    fn test_default_status_is_stopped() {
89        let service = TestService;
90        assert_eq!(service.status(), ServiceStatus::Stopped);
91    }
92}