Skip to main content

mecha10_cli/services/process/
control.rs

1//! Status, stop/restart, and cleanup operations for `ProcessService`
2
3use super::ProcessService;
4use anyhow::Result;
5use std::collections::HashMap;
6
7impl ProcessService {
8    /// Get status of all processes
9    ///
10    /// Returns a HashMap mapping process names to status strings
11    pub fn get_status(&mut self) -> HashMap<String, String> {
12        use mecha10_runtime::ProcessStatus;
13
14        self.manager
15            .status_all()
16            .into_iter()
17            .map(|(name, status)| {
18                let status_str = match status {
19                    ProcessStatus::Running => "running".to_string(),
20                    ProcessStatus::Exited(code) => format!("exited (code: {})", code),
21                    ProcessStatus::Error => "error".to_string(),
22                };
23                (name, status_str)
24            })
25            .collect()
26    }
27
28    /// Stop a specific process by name
29    ///
30    /// # Arguments
31    ///
32    /// * `name` - Name of the process to stop
33    ///
34    /// # Errors
35    ///
36    /// Returns an error if the process is not found
37    ///
38    /// Note: This uses a default 10-second timeout for graceful shutdown.
39    /// Use stop_with_timeout() for custom timeout.
40    pub fn stop(&mut self, name: &str) -> Result<()> {
41        self.manager.stop_graceful(name, std::time::Duration::from_secs(10))
42    }
43
44    /// Stop a process with timeout for graceful shutdown
45    ///
46    /// Tries graceful shutdown (SIGTERM on Unix), then force kills after timeout
47    ///
48    /// # Arguments
49    ///
50    /// * `name` - Name of the process to stop
51    /// * `timeout` - How long to wait for graceful shutdown
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if process not found or cannot be stopped
56    pub fn stop_with_timeout(&mut self, name: &str, timeout: std::time::Duration) -> Result<()> {
57        self.manager.stop_graceful(name, timeout)
58    }
59
60    /// Force kill a process by name
61    ///
62    /// # Arguments
63    ///
64    // duplicate: false positive (LAB-2570) — one-line delegation to
65    // `mecha10_runtime::ProcessManager::force_kill`, matched against other unrelated
66    // single-argument delegator methods purely on AST shape (e.g. `NodeRegistry::mark_exited` in
67    // handlers/dev/ops/registry.rs). The actual kill logic already lives once, in the runtime's
68    // `ProcessManager`; this is just the CLI-facing name for it.
69    /// * `name` - Name of the process to kill
70    pub fn force_kill(&mut self, name: &str) -> Result<()> {
71        self.manager.force_kill(name)
72    }
73
74    /// Stop all processes gracefully in dependency order
75    ///
76    /// This delegates to the runtime's ProcessManager which handles:
77    /// - Dependency-based shutdown ordering
78    /// - Graceful shutdown with timeout
79    /// - Force kill fallback
80    pub fn cleanup(&mut self) {
81        self.manager.shutdown_all();
82    }
83
84    /// Check if a process is running
85    ///
86    /// # Arguments
87    ///
88    // duplicate: false positive (LAB-2570) — one-line delegation to
89    // `mecha10_runtime::ProcessManager::is_running`, matched against `NodeRegistry::is_running`
90    // (handlers/dev/ops/registry.rs) and `CliLifecycleManager::has_mode`
91    // (dev/lifecycle_adapter.rs) on AST shape only: this queries the runtime's live process
92    // table, `NodeRegistry`'s is a separate CLI-owned bookkeeping map of PIDs/failures (see
93    // LAB-1891) - different data, no shared logic to extract.
94    /// * `name` - Name of the process to check
95    pub fn is_running(&mut self, name: &str) -> bool {
96        self.manager.is_running(name)
97    }
98
99    /// Restart a specific process
100    ///
101    /// Stops the process if running and starts it again
102    ///
103    /// # Arguments
104    ///
105    /// * `name` - Name of the process
106    /// * `binary_path` - Path to the binary
107    /// * `args` - Command-line arguments
108    pub fn restart(&mut self, name: &str, binary_path: &str, args: &[&str]) -> Result<u32> {
109        if self.is_running(name) {
110            self.stop(name)?;
111            std::thread::sleep(std::time::Duration::from_millis(100));
112        }
113
114        self.spawn_node(name, binary_path, args)
115    }
116
117    /// Restart all processes
118    ///
119    /// # Arguments
120    ///
121    /// * `nodes` - Vec of (name, binary_path, args) tuples
122    pub fn restart_all(&mut self, nodes: Vec<(&str, &str, Vec<&str>)>) -> Result<HashMap<String, u32>> {
123        self.cleanup();
124
125        std::thread::sleep(std::time::Duration::from_millis(500));
126
127        self.spawn_nodes(nodes)
128    }
129}