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}