Skip to main content

systemprompt_scheduler/services/
service_management.rs

1use anyhow::Result;
2use systemprompt_database::{DbPool, ServiceConfig, ServiceRepository};
3use tracing::warn;
4
5use super::orchestration::ProcessCleanup;
6
7#[derive(Clone, Debug)]
8pub struct ServiceManagementService {
9    service_repo: ServiceRepository,
10}
11
12impl ServiceManagementService {
13    pub const fn new(db_pool: DbPool) -> Self {
14        Self {
15            service_repo: ServiceRepository::new(db_pool),
16        }
17    }
18
19    pub async fn get_services_by_type(&self, module_name: &str) -> Result<Vec<ServiceConfig>> {
20        self.service_repo.get_services_by_type(module_name).await
21    }
22
23    pub async fn get_running_services_with_pid(&self) -> Result<Vec<ServiceConfig>> {
24        self.service_repo.get_running_services_with_pid().await
25    }
26
27    pub async fn mark_service_stopped(&self, service_name: &str) -> Result<()> {
28        self.service_repo.update_service_stopped(service_name).await
29    }
30
31    pub async fn cleanup_stale_entries(&self) -> Result<u64> {
32        self.service_repo.cleanup_stale_entries().await
33    }
34
35    pub async fn stop_service(&self, service: &ServiceConfig, force: bool) -> Result<()> {
36        if let Some(pid) = service.pid {
37            if force {
38                ProcessCleanup::kill_process(pid as u32);
39            } else {
40                ProcessCleanup::terminate_gracefully(pid as u32, 100).await;
41            }
42        }
43
44        ProcessCleanup::kill_port(service.port as u16);
45        if let Err(e) = self.mark_service_stopped(&service.name).await {
46            warn!(service = %service.name, error = %e, "Failed to mark service stopped");
47        }
48        Ok(())
49    }
50
51    pub async fn cleanup_orphaned_service(&self, service: &ServiceConfig) -> Result<bool> {
52        if let Some(pid) = service.pid {
53            let pid = pid as u32;
54
55            if !ProcessCleanup::process_exists(pid) {
56                if let Err(e) = self.mark_service_stopped(&service.name).await {
57                    warn!(service = %service.name, error = %e, "Failed to mark orphaned service stopped");
58                }
59                return Ok(true);
60            }
61
62            ProcessCleanup::terminate_gracefully(pid, 100).await;
63            ProcessCleanup::kill_port(service.port as u16);
64            if let Err(e) = self.mark_service_stopped(&service.name).await {
65                warn!(service = %service.name, error = %e, "Failed to mark terminated service stopped");
66            }
67            return Ok(true);
68        }
69        Ok(false)
70    }
71}