mcp_runner/server/
lifecycle.rs

1//! Server lifecycle management for MCP servers.
2//!
3//! This module provides functionality to track and manage the lifecycle of MCP servers,
4//! including recording lifecycle events, tracking server status changes, and retrieving
5//! event history.
6
7use crate::error::{Error, Result};
8use crate::server::{ServerId, ServerStatus};
9use std::collections::HashMap;
10use std::sync::{Arc, Mutex};
11use std::time::Instant;
12use tracing; // Import tracing
13
14/// Server lifecycle event types
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ServerLifecycleEvent {
17    /// Server started
18    Started,
19    /// Server stopped
20    Stopped,
21    /// Server failed
22    Failed,
23    /// Server restarted
24    Restarted,
25}
26
27/// Server lifecycle event
28///
29/// Represents a single event in a server's lifecycle, including details about
30/// what happened and when it occurred.
31#[derive(Debug, Clone)]
32pub struct ServerEvent {
33    /// Server ID
34    pub id: ServerId,
35    /// Server name
36    pub name: String,
37    /// Event type
38    pub event: ServerLifecycleEvent,
39    /// Event timestamp
40    pub timestamp: Instant,
41    /// Event details
42    pub details: Option<String>,
43}
44
45/// Server lifecycle manager
46///
47/// Manages the lifecycle events and status for MCP servers.
48/// All public methods are instrumented with `tracing` spans.
49pub struct ServerLifecycleManager {
50    /// Server events
51    events: Arc<Mutex<Vec<ServerEvent>>>,
52    /// Server statuses
53    statuses: Arc<Mutex<HashMap<ServerId, ServerStatus>>>,
54}
55
56impl ServerLifecycleManager {
57    /// Create a new server lifecycle manager
58    pub fn new() -> Self {
59        Self {
60            events: Arc::new(Mutex::new(Vec::new())),
61            statuses: Arc::new(Mutex::new(HashMap::new())),
62        }
63    }
64
65    /// Record a server event
66    ///
67    /// Records a lifecycle event for a server and updates its status accordingly.
68    /// This method is instrumented with `tracing`.
69    ///
70    /// # Arguments
71    ///
72    /// * `id` - The ID of the server
73    /// * `name` - The name of the server
74    /// * `event` - The lifecycle event type
75    /// * `details` - Optional details about the event
76    ///
77    /// # Returns
78    ///
79    /// A `Result` indicating success or failure
80    #[tracing::instrument(skip(self), fields(server_id = %id, server_name = %name, event_type = ?event))]
81    pub fn record_event(
82        &self,
83        id: ServerId,
84        name: String,
85        event: ServerLifecycleEvent,
86        details: Option<String>,
87    ) -> Result<()> {
88        tracing::info!(details = ?details, "Recording server lifecycle event");
89        let server_event = ServerEvent {
90            id,
91            name,
92            event,
93            timestamp: Instant::now(),
94            details,
95        };
96
97        // Update status
98        {
99            let mut statuses = self.statuses.lock().map_err(|_| {
100                tracing::error!("Failed to lock server statuses");
101                Error::Other("Failed to lock server statuses".to_string())
102            })?;
103
104            let status = match event {
105                ServerLifecycleEvent::Started => ServerStatus::Running,
106                ServerLifecycleEvent::Stopped => ServerStatus::Stopped,
107                ServerLifecycleEvent::Failed => ServerStatus::Failed,
108                ServerLifecycleEvent::Restarted => ServerStatus::Running,
109            };
110
111            tracing::debug!(new_status = ?status, "Updating server status");
112            statuses.insert(id, status);
113        }
114
115        // Record event
116        {
117            let mut events = self.events.lock().map_err(|_| {
118                tracing::error!("Failed to lock server events");
119                Error::Other("Failed to lock server events".to_string())
120            })?;
121
122            events.push(server_event);
123            tracing::debug!(total_events = events.len(), "Added event to history");
124
125            // Limit event history
126            if events.len() > 1000 {
127                tracing::trace!("Trimming event history (exceeded 1000 events)");
128                events.remove(0);
129            }
130        }
131
132        tracing::info!("Successfully recorded server event");
133        Ok(())
134    }
135
136    /// Get server status
137    ///
138    /// Retrieves the current status of a server.
139    ///
140    /// # Arguments
141    ///
142    /// * `id` - The ID of the server
143    ///
144    /// # Returns
145    ///
146    /// A `Result<ServerStatus>` containing the server's status if successful
147    pub fn get_status(&self, id: ServerId) -> Result<ServerStatus> {
148        let statuses = self
149            .statuses
150            .lock()
151            .map_err(|_| Error::Other("Failed to lock server statuses".to_string()))?;
152
153        statuses
154            .get(&id)
155            .copied()
156            .ok_or_else(|| Error::ServerNotFound(format!("{:?}", id)))
157    }
158
159    /// Get recent events for a server
160    ///
161    /// Retrieves a list of recent events for a specific server, sorted by
162    /// timestamp with newest events first.
163    ///
164    /// # Arguments
165    ///
166    /// * `id` - The ID of the server
167    /// * `limit` - Optional maximum number of events to return
168    ///
169    /// # Returns
170    ///
171    /// A `Result<Vec<ServerEvent>>` containing the server events if successful
172    pub fn get_server_events(
173        &self,
174        id: ServerId,
175        limit: Option<usize>,
176    ) -> Result<Vec<ServerEvent>> {
177        let events = self
178            .events
179            .lock()
180            .map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
181
182        let mut server_events: Vec<ServerEvent> =
183            events.iter().filter(|e| e.id == id).cloned().collect();
184
185        // Sort by timestamp (newest first)
186        server_events.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
187
188        // Apply limit
189        if let Some(limit) = limit {
190            server_events.truncate(limit);
191        }
192
193        Ok(server_events)
194    }
195
196    /// Get all events
197    ///
198    /// Retrieves all server events across all servers, sorted by
199    /// timestamp with newest events first.
200    ///
201    /// # Arguments
202    ///
203    /// * `limit` - Optional maximum number of events to return
204    ///
205    /// # Returns
206    ///
207    /// A `Result<Vec<ServerEvent>>` containing all events if successful
208    pub fn get_all_events(&self, limit: Option<usize>) -> Result<Vec<ServerEvent>> {
209        let events = self
210            .events
211            .lock()
212            .map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
213
214        let mut all_events = events.clone();
215
216        // Sort by timestamp (newest first)
217        all_events.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
218
219        // Apply limit
220        if let Some(limit) = limit {
221            all_events.truncate(limit);
222        }
223
224        Ok(all_events)
225    }
226
227    /// Clear events
228    ///
229    /// Removes all stored server events.
230    ///
231    /// # Returns
232    ///
233    /// A `Result<()>` indicating success or failure
234    pub fn clear_events(&self) -> Result<()> {
235        let mut events = self
236            .events
237            .lock()
238            .map_err(|_| Error::Other("Failed to lock server events".to_string()))?;
239
240        events.clear();
241
242        Ok(())
243    }
244}
245
246impl Default for ServerLifecycleManager {
247    fn default() -> Self {
248        Self::new()
249    }
250}