systemprompt_scheduler/services/
service_management.rs1use 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}