use crate::service::Service;
use crate::{HealthStatus, Result};
use async_trait::async_trait;
use tokio::sync::broadcast;
use tracing::{debug, error, info};
#[async_trait]
trait ServiceWrapper: Send + Sync {
async fn start(&mut self) -> Result<()>;
async fn stop(&mut self) -> Result<()>;
async fn health_check(&self) -> HealthStatus;
fn name(&self) -> &str;
}
struct ServiceBox<S: Service> {
service: S,
}
#[async_trait]
impl<S: Service> ServiceWrapper for ServiceBox<S> {
async fn start(&mut self) -> Result<()> {
self.service.start().await
}
async fn stop(&mut self) -> Result<()> {
self.service.stop().await
}
async fn health_check(&self) -> HealthStatus {
self.service.health_check().await
}
fn name(&self) -> &str {
self.service.name()
}
}
pub struct ServiceManager {
services: Vec<Box<dyn ServiceWrapper>>,
shutdown_tx: broadcast::Sender<()>,
}
impl ServiceManager {
pub fn new() -> Self {
let (shutdown_tx, _) = broadcast::channel(1);
Self {
services: Vec::new(),
shutdown_tx,
}
}
pub async fn register<S>(&mut self, config: S::Config) -> Result<()>
where
S: Service + 'static,
{
debug!("Registering service: {}", std::any::type_name::<S>());
let service = S::init(config).await?;
let name = service.name().to_string();
let boxed = Box::new(ServiceBox { service });
self.services.push(boxed);
info!("Registered service: {}", name);
Ok(())
}
pub async fn start_all(&mut self) -> Result<()> {
info!("Starting {} services", self.services.len());
for service in &mut self.services {
let name = service.name().to_string();
debug!("Starting service: {}", name);
if let Err(e) = service.start().await {
error!("Failed to start service '{}': {}", name, e);
return Err(e);
}
info!("Started service: {}", name);
}
info!("All services started successfully");
Ok(())
}
pub async fn stop_all(&mut self) -> Result<()> {
info!("Stopping {} services (in reverse order)", self.services.len());
let mut first_error = None;
for service in self.services.iter_mut().rev() {
let name = service.name().to_string();
debug!("Stopping service: {}", name);
match service.stop().await {
Ok(()) => {
info!("Stopped service: {}", name);
}
Err(e) => {
error!("Failed to stop service '{}': {}", name, e);
if first_error.is_none() {
first_error = Some(e);
}
}
}
}
if let Some(err) = first_error {
error!("Service manager stopped with errors");
Err(err)
} else {
info!("All services stopped successfully");
Ok(())
}
}
pub async fn health_check_all(&self) -> Vec<(String, HealthStatus)> {
let mut results = Vec::new();
for service in &self.services {
let name = service.name().to_string();
let status = service.health_check().await;
debug!("Health check for '{}': healthy={}", name, status.healthy);
results.push((name, status));
}
results
}
pub fn shutdown_signal(&self) -> broadcast::Receiver<()> {
self.shutdown_tx.subscribe()
}
pub fn shutdown(&self) {
info!("Broadcasting shutdown signal");
let _ = self.shutdown_tx.send(());
}
pub fn service_count(&self) -> usize {
self.services.len()
}
pub fn service_names(&self) -> Vec<String> {
self.services.iter().map(|s| s.name().to_string()).collect()
}
}
impl Default for ServiceManager {
fn default() -> Self {
Self::new()
}
}