Skip to main content

systemprompt_cli/commands/infrastructure/services/restart/
single.rs

1//! Single-service restart.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use crate::cli_settings::CliConfig;
7use crate::interactive::Prompter;
8use crate::shared::CommandOutput;
9use anyhow::Result;
10use std::sync::Arc;
11use systemprompt_logging::CliService;
12use systemprompt_runtime::AppContext;
13use systemprompt_scheduler::ProcessCleanup;
14
15use super::super::lifecycle;
16use super::super::types::RestartOutput;
17
18pub async fn execute_api(prompter: &dyn Prompter, config: &CliConfig) -> Result<CommandOutput> {
19    let quiet = config.is_json_output();
20
21    if !quiet {
22        CliService::section("Restarting API Server");
23    }
24
25    let port = super::get_api_port();
26    let Some(pid) = ProcessCleanup::check_port(port) else {
27        if !quiet {
28            CliService::warning("API server is not running");
29            CliService::info("Starting API server...");
30        }
31        super::super::serve::execute(prompter, true, false, config).await?;
32        let output = RestartOutput {
33            service_type: "api".to_owned(),
34            service_name: None,
35            restarted_count: 1,
36            failed_count: 0,
37            message: "API server started (was not running)".to_owned(),
38        };
39        return Ok(CommandOutput::card_value("Restart API Server", &output));
40    };
41
42    if !quiet {
43        CliService::info(&format!("Stopping API server (PID: {})...", pid));
44    }
45
46    ProcessCleanup::terminate_gracefully(pid, 100).await;
47    ProcessCleanup::kill_port(port, pid);
48
49    ProcessCleanup::wait_for_port_free(port, 5, 500).await?;
50
51    if !quiet {
52        CliService::success("API server stopped");
53        CliService::info("Starting API server...");
54    }
55
56    super::super::serve::execute(prompter, true, false, config).await?;
57
58    let message = "API server restarted successfully".to_owned();
59    if !quiet {
60        CliService::success(&message);
61    }
62
63    let output = RestartOutput {
64        service_type: "api".to_owned(),
65        service_name: None,
66        restarted_count: 1,
67        failed_count: 0,
68        message,
69    };
70
71    Ok(CommandOutput::card_value("Restart API Server", &output))
72}
73
74pub async fn execute_agent(
75    ctx: &Arc<AppContext>,
76    agent: &str,
77    config: &CliConfig,
78) -> Result<CommandOutput> {
79    let quiet = config.is_json_output();
80
81    if !quiet {
82        CliService::section(&format!("Restarting Agent: {}", agent));
83    }
84
85    let orchestrator = lifecycle::agent_orchestrator(ctx).await?;
86    let name = lifecycle::resolve_agent_name(agent).await?;
87    let service_id = orchestrator.restart_agent(&name, None).await?;
88
89    let message = format!(
90        "Agent {} restarted successfully (service ID: {})",
91        agent, service_id
92    );
93    if !quiet {
94        CliService::success(&message);
95    }
96
97    let output = RestartOutput {
98        service_type: "agent".to_owned(),
99        service_name: Some(agent.to_owned()),
100        restarted_count: 1,
101        failed_count: 0,
102        message,
103    };
104
105    Ok(CommandOutput::card_value("Restart Agent", &output))
106}
107
108pub async fn execute_mcp(
109    ctx: &Arc<AppContext>,
110    server_name: &str,
111    build: bool,
112    config: &CliConfig,
113) -> Result<CommandOutput> {
114    let quiet = config.is_json_output();
115    let action = if build {
116        "Building and restarting"
117    } else {
118        "Restarting"
119    };
120
121    if !quiet {
122        CliService::section(&format!("{} MCP Server: {}", action, server_name));
123    }
124
125    let manager = lifecycle::mcp_orchestrator(ctx)?;
126
127    if build {
128        manager
129            .build_and_restart_services(Some(server_name.to_owned()))
130            .await?;
131    } else {
132        manager
133            .restart_services_sync(Some(server_name.to_owned()))
134            .await?;
135    }
136
137    let message = format!("MCP server {} restarted successfully", server_name);
138    if !quiet {
139        CliService::success(&message);
140    }
141
142    let output = RestartOutput {
143        service_type: "mcp".to_owned(),
144        service_name: Some(server_name.to_owned()),
145        restarted_count: 1,
146        failed_count: 0,
147        message,
148    };
149
150    Ok(CommandOutput::card_value("Restart MCP Server", &output))
151}