#![cfg_attr(coverage_nightly, coverage(off))]
use super::service_base::{Service, ServiceMetrics};
use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tokio::sync::RwLock;
use tokio::time::{interval, Duration};
use tracing::{error, info, warn};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ServiceState {
Uninitialized,
Starting,
Running,
Degraded,
Stopping,
Stopped,
Failed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthStatus {
pub state: ServiceState,
pub message: String,
pub last_check: std::time::SystemTime,
pub uptime_seconds: u64,
pub metrics: ServiceMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LifecycleEvent {
Started,
Stopped,
HealthCheckPassed,
HealthCheckFailed(String),
StateChanged(ServiceState),
Error(String),
}
#[async_trait]
pub trait ManagedService: Service {
async fn initialize(&self) -> Result<()> {
Ok(())
}
async fn health_check(&self) -> Result<HealthStatus>;
async fn shutdown(&self) -> Result<()> {
Ok(())
}
fn handle_event(&mut self, event: LifecycleEvent) {
if let LifecycleEvent::Error(msg) = event {
error!("Service error: {}", msg);
}
}
}
pub struct LifecycleWrapper<S: Service> {
service: Arc<RwLock<S>>,
state: Arc<RwLock<ServiceState>>,
running: Arc<AtomicBool>,
start_time: std::time::SystemTime,
health_check_interval: Duration,
metrics: Arc<RwLock<ServiceMetrics>>,
}
type ManagedServiceObject = dyn ManagedService<Input = serde_json::Value, Output = serde_json::Value, Error = anyhow::Error>
+ Send
+ Sync;
pub struct ServiceSupervisor {
services: Arc<RwLock<Vec<Arc<ManagedServiceObject>>>>,
running: Arc<AtomicBool>,
}
include!("service_lifecycle_wrapper.rs");
include!("service_lifecycle_supervisor.rs");
include!("service_lifecycle_tests.rs");