systemprompt_cli/commands/infrastructure/services/
restart.rs1use crate::cli_settings::CliConfig;
2use anyhow::{Context, Result};
3use std::sync::Arc;
4use systemprompt_agent::services::agent_orchestration::AgentOrchestrator;
5use systemprompt_agent::services::registry::AgentRegistry;
6use systemprompt_agent::AgentState;
7use systemprompt_logging::CliService;
8use systemprompt_mcp::services::McpManager;
9use systemprompt_models::ProfileBootstrap;
10use systemprompt_oauth::JwtValidationProviderImpl;
11use systemprompt_runtime::AppContext;
12use systemprompt_scheduler::ProcessCleanup;
13
14const DEFAULT_API_PORT: u16 = 8080;
15
16fn create_agent_state(ctx: &AppContext) -> Result<Arc<AgentState>> {
17 let jwt_provider = Arc::new(
18 JwtValidationProviderImpl::from_config().context("Failed to create JWT provider")?,
19 );
20 Ok(Arc::new(AgentState::new(
21 Arc::clone(ctx.db_pool()),
22 Arc::new(ctx.config().clone()),
23 jwt_provider,
24 )))
25}
26
27fn get_api_port() -> u16 {
28 ProfileBootstrap::get()
29 .map(|p| p.server.port)
30 .unwrap_or(DEFAULT_API_PORT)
31}
32
33async fn resolve_name(agent_identifier: &str) -> Result<String> {
34 let registry = AgentRegistry::new().await?;
35 let agent = registry.get_agent(agent_identifier).await?;
36 Ok(agent.name)
37}
38
39pub async fn execute_api(config: &CliConfig) -> Result<()> {
40 CliService::section("Restarting API Server");
41
42 let port = get_api_port();
43 let Some(pid) = ProcessCleanup::check_port(port) else {
44 CliService::warning("API server is not running");
45 CliService::info("Starting API server...");
46 return super::serve::execute(true, false, config).await;
47 };
48 CliService::info(&format!("Stopping API server (PID: {})...", pid));
49
50 ProcessCleanup::terminate_gracefully(pid, 100).await;
51 ProcessCleanup::kill_port(port);
52
53 ProcessCleanup::wait_for_port_free(port, 5, 500).await?;
54
55 CliService::success("API server stopped");
56 CliService::info("Starting API server...");
57
58 super::serve::execute(true, false, config).await?;
59
60 CliService::success("API server restarted successfully");
61 Ok(())
62}
63
64pub async fn execute_agent(
65 ctx: &Arc<AppContext>,
66 agent_id: &str,
67 _config: &CliConfig,
68) -> Result<()> {
69 CliService::section(&format!("Restarting Agent: {}", agent_id));
70
71 let agent_state = create_agent_state(ctx)?;
72 let orchestrator = AgentOrchestrator::new(agent_state, None)
73 .await
74 .context("Failed to initialize agent orchestrator")?;
75
76 let name = resolve_name(agent_id).await?;
77 let service_id = orchestrator.restart_agent(&name, None).await?;
78
79 CliService::success(&format!(
80 "Agent {} restarted successfully (service ID: {})",
81 agent_id, service_id
82 ));
83
84 Ok(())
85}
86
87pub async fn execute_mcp(
88 ctx: &Arc<AppContext>,
89 server_name: &str,
90 build: bool,
91 _config: &CliConfig,
92) -> Result<()> {
93 let action = if build {
94 "Building and restarting"
95 } else {
96 "Restarting"
97 };
98 CliService::section(&format!("{} MCP Server: {}", action, server_name));
99
100 let manager =
101 McpManager::new(Arc::clone(ctx.db_pool())).context("Failed to initialize MCP manager")?;
102
103 if build {
104 manager
105 .build_and_restart_services(Some(server_name.to_string()))
106 .await?;
107 } else {
108 manager
109 .restart_services_sync(Some(server_name.to_string()))
110 .await?;
111 }
112
113 CliService::success(&format!(
114 "MCP server {} restarted successfully",
115 server_name
116 ));
117
118 Ok(())
119}
120
121pub async fn execute_all_agents(ctx: &Arc<AppContext>, _config: &CliConfig) -> Result<()> {
122 CliService::section("Restarting All Agents");
123
124 let agent_state = create_agent_state(ctx)?;
125 let orchestrator = AgentOrchestrator::new(agent_state, None)
126 .await
127 .context("Failed to initialize agent orchestrator")?;
128
129 let agent_registry = AgentRegistry::new().await?;
130 let all_agents = orchestrator.list_all().await?;
131
132 let mut restarted = 0i32;
133 let mut failed = 0i32;
134
135 for (agent_id, _status) in &all_agents {
136 let Ok(agent_config) = agent_registry.get_agent(agent_id).await else {
137 continue;
138 };
139
140 if !agent_config.enabled {
141 continue;
142 }
143
144 CliService::info(&format!("Restarting agent: {}", agent_config.name));
145 match orchestrator.restart_agent(agent_id, None).await {
146 Ok(_) => {
147 restarted += 1;
148 CliService::success(&format!(" {} restarted", agent_config.name));
149 },
150 Err(e) => {
151 failed += 1;
152 CliService::error(&format!(" Failed to restart {}: {}", agent_config.name, e));
153 },
154 }
155 }
156
157 match (restarted, failed) {
158 (0, 0) => CliService::info("No enabled agents found"),
159 (r, 0) => CliService::success(&format!("Restarted {} agents", r)),
160 (0, f) => CliService::warning(&format!("Failed to restart {} agents", f)),
161 (r, f) => {
162 CliService::success(&format!("Restarted {} agents", r));
163 CliService::warning(&format!("Failed to restart {} agents", f));
164 },
165 }
166
167 Ok(())
168}
169
170pub async fn execute_all_mcp(ctx: &Arc<AppContext>, _config: &CliConfig) -> Result<()> {
171 CliService::section("Restarting All MCP Servers");
172
173 let mcp_manager =
174 McpManager::new(Arc::clone(ctx.db_pool())).context("Failed to initialize MCP manager")?;
175
176 systemprompt_mcp::services::RegistryManager::validate()?;
177 let servers = systemprompt_mcp::services::RegistryManager::get_enabled_servers()?;
178
179 let mut restarted = 0i32;
180 let mut failed = 0i32;
181
182 for server in servers {
183 if !server.enabled {
184 continue;
185 }
186
187 CliService::info(&format!("Restarting MCP server: {}", server.name));
188 match mcp_manager
189 .restart_services(Some(server.name.clone()))
190 .await
191 {
192 Ok(()) => {
193 restarted += 1;
194 CliService::success(&format!(" {} restarted", server.name));
195 },
196 Err(e) => {
197 failed += 1;
198 CliService::error(&format!(" Failed to restart {}: {}", server.name, e));
199 },
200 }
201 }
202
203 match (restarted, failed) {
204 (0, 0) => CliService::info("No enabled MCP servers found"),
205 (r, 0) => CliService::success(&format!("Restarted {} MCP servers", r)),
206 (0, f) => CliService::warning(&format!("Failed to restart {} MCP servers", f)),
207 (r, f) => {
208 CliService::success(&format!("Restarted {} MCP servers", r));
209 CliService::warning(&format!("Failed to restart {} MCP servers", f));
210 },
211 }
212
213 Ok(())
214}
215
216pub async fn execute_failed(ctx: &Arc<AppContext>, _config: &CliConfig) -> Result<()> {
217 CliService::section("Restarting Failed Services");
218
219 let mut restarted_count = 0;
220 let mut failed_count = 0;
221
222 restart_failed_agents(ctx, &mut restarted_count, &mut failed_count).await?;
223 restart_failed_mcp(ctx, &mut restarted_count, &mut failed_count).await?;
224
225 if restarted_count > 0 {
226 CliService::success(&format!("Restarted {} failed services", restarted_count));
227 } else {
228 CliService::info("No failed services found");
229 }
230
231 if failed_count > 0 {
232 CliService::warning(&format!("Failed to restart {} services", failed_count));
233 }
234
235 Ok(())
236}
237
238async fn restart_failed_agents(
239 ctx: &Arc<AppContext>,
240 restarted_count: &mut i32,
241 failed_count: &mut i32,
242) -> Result<()> {
243 let agent_state = create_agent_state(ctx)?;
244 let orchestrator = AgentOrchestrator::new(agent_state, None)
245 .await
246 .context("Failed to initialize agent orchestrator")?;
247
248 let agent_registry = AgentRegistry::new().await?;
249
250 let all_agents = orchestrator.list_all().await?;
251 for (agent_id, status) in &all_agents {
252 let Ok(agent_config) = agent_registry.get_agent(agent_id).await else {
253 continue;
254 };
255
256 if !agent_config.enabled {
257 continue;
258 }
259
260 if let systemprompt_agent::services::agent_orchestration::AgentStatus::Failed { .. } =
261 status
262 {
263 CliService::info(&format!("Restarting failed agent: {}", agent_config.name));
264 match orchestrator.restart_agent(agent_id, None).await {
265 Ok(_) => {
266 *restarted_count += 1;
267 CliService::success(&format!(" {} restarted", agent_config.name));
268 },
269 Err(e) => {
270 *failed_count += 1;
271 CliService::error(&format!(" Failed to restart {}: {}", agent_config.name, e));
272 },
273 }
274 }
275 }
276
277 Ok(())
278}
279
280async fn restart_failed_mcp(
281 ctx: &Arc<AppContext>,
282 restarted_count: &mut i32,
283 failed_count: &mut i32,
284) -> Result<()> {
285 let mcp_manager =
286 McpManager::new(Arc::clone(ctx.db_pool())).context("Failed to initialize MCP manager")?;
287
288 systemprompt_mcp::services::RegistryManager::validate()?;
289 let servers = systemprompt_mcp::services::RegistryManager::get_enabled_servers()?;
290
291 for server in servers {
292 if !server.enabled {
293 continue;
294 }
295
296 let database = systemprompt_mcp::services::DatabaseManager::new(Arc::clone(ctx.db_pool()));
297 let service_info = database.get_service_by_name(&server.name).await?;
298
299 let needs_restart = match service_info {
300 Some(info) => info.status != "running",
301 None => true,
302 };
303
304 if needs_restart {
305 CliService::info(&format!("Restarting MCP server: {}", server.name));
306 match mcp_manager
307 .restart_services(Some(server.name.clone()))
308 .await
309 {
310 Ok(()) => {
311 *restarted_count += 1;
312 CliService::success(&format!(" {} restarted", server.name));
313 },
314 Err(e) => {
315 *failed_count += 1;
316 CliService::error(&format!(" Failed to restart {}: {}", server.name, e));
317 },
318 }
319 }
320 }
321
322 Ok(())
323}