grove/Host/
Lifecycle.rs

1//! Lifecycle Management Module
2//!
3//! Handles extension lifecycle events such as initialization,
4//! shutdown, and state transitions.
5
6use std::{collections::HashMap, sync::Arc};
7
8use anyhow::{Context, Result};
9use serde::{Deserialize, Serialize};
10use tokio::sync::RwLock;
11use tracing::{debug, info, instrument, warn};
12
13/// Lifecycle event types
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15pub enum LifecycleEvent {
16	/// Extension is being initialized
17	Initialize,
18	/// Extension is being started
19	Start,
20	/// Extension is being stopped
21	Stop,
22	/// Extension is being disposed
23	Dispose,
24	/// Extension is reloading (hot reload)
25	Reload,
26	/// Extension is being suspended
27	Suspend,
28	/// Extension is being resumed
29	Resume,
30	/// Custom lifecycle event
31	Custom(String),
32}
33
34/// Lifecycle state for extensions
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
36pub enum LifecycleState {
37	/// Extension has been created but not initialized
38	Created,
39	/// Extension is being initialized
40	Initializing,
41	/// Extension is active and running
42	Running,
43	/// Extension is being suspended
44	Suspending,
45	/// Extension is suspended
46	Suspended,
47	/// Extension is being stopped
48	Stopping,
49	/// Extension has been stopped
50	Stopped,
51	/// Extension is being disposed
52	Disposing,
53	/// Extension has been disposed
54	Disposed,
55	/// Extension is in an error state
56	Error,
57}
58
59/// Lifecycle event handler callback
60type LifecycleEventHandler = fn(&str, LifecycleEvent) -> Result<()>;
61
62/// Lifecycle manager for extension lifecycle
63pub struct LifecycleManager {
64	/// Event handlers
65	handlers:Arc<RwLock<HashMap<String, LifecycleHandlerInfo>>>,
66	/// Extension states
67	states:Arc<RwLock<HashMap<String, LifecycleState>>>,
68	/// Event history
69	event_history:Arc<RwLock<Vec<LifecycleEventRecord>>>,
70}
71
72/// Information about a lifecycle handler
73#[derive(Debug, Clone)]
74struct LifecycleHandlerInfo {
75	/// Extension ID
76	extension_id:String,
77	/// Current state
78	state:LifecycleState,
79	/// Supported events
80	supported_events:Vec<LifecycleEvent>,
81	/// Last state change timestamp
82	last_state_change:Option<u64>,
83}
84
85/// Record of a lifecycle event
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct LifecycleEventRecord {
88	/// Extension ID
89	pub extension_id:String,
90	/// Event that occurred
91	pub event:LifecycleEvent,
92	/// Previous state
93	pub previous_state:LifecycleState,
94	/// New state
95	pub new_state:LifecycleState,
96	/// Timestamp
97	pub timestamp:u64,
98	/// Duration in milliseconds
99	pub duration_ms:u64,
100	/// Success flag
101	pub success:bool,
102	/// Error message (if failed)
103	pub error:Option<String>,
104}
105
106impl LifecycleManager {
107	/// Create a new lifecycle manager
108	pub fn new() -> Self {
109		Self {
110			handlers:Arc::new(RwLock::new(HashMap::new())),
111			states:Arc::new(RwLock::new(HashMap::new())),
112			event_history:Arc::new(RwLock::new(Vec::new())),
113		}
114	}
115
116	/// Register an extension for lifecycle management
117	#[instrument(skip(self, extension_id))]
118	pub async fn register_extension(&self, extension_id:&str, initial_state:LifecycleState) -> Result<()> {
119		info!("Registering extension for lifecycle management: {}", extension_id);
120
121		let mut handlers = self.handlers.write().await;
122		handlers.insert(
123			extension_id.to_string(),
124			LifecycleHandlerInfo {
125				extension_id:extension_id.to_string(),
126				state:initial_state,
127				supported_events:vec![
128					LifecycleEvent::Initialize,
129					LifecycleEvent::Start,
130					LifecycleEvent::Stop,
131					LifecycleEvent::Dispose,
132				],
133				last_state_change:Some(
134					std::time::SystemTime::now()
135						.duration_since(std::time::UNIX_EPOCH)
136						.map(|d| d.as_secs())
137						.unwrap_or(0),
138				),
139			},
140		);
141
142		let mut states = self.states.write().await;
143		states.insert(extension_id.to_string(), initial_state);
144
145		debug!("Extension registered: {}", extension_id);
146
147		Ok(())
148	}
149
150	/// Unregister an extension from lifecycle management
151	#[instrument(skip(self, extension_id))]
152	pub async fn unregister_extension(&self, extension_id:&str) -> Result<()> {
153		info!("Unregistering extension from lifecycle management: {}", extension_id);
154
155		let mut handlers = self.handlers.write().await;
156		handlers.remove(extension_id);
157
158		let mut states = self.states.write().await;
159		states.remove(extension_id);
160
161		debug!("Extension unregistered: {}", extension_id);
162
163		Ok(())
164	}
165
166	/// Get the current state of an extension
167	pub async fn get_state(&self, extension_id:&str) -> Option<LifecycleState> {
168		self.states.read().await.get(extension_id).copied()
169	}
170
171	/// Transition an extension to a new state
172	#[instrument(skip(self, extension_id, event))]
173	pub async fn transition(&self, extension_id:&str, event:LifecycleEvent) -> Result<LifecycleState> {
174		info!("Transitioning extension {} with event: {:?}", extension_id, event);
175
176		let start = std::time::Instant::now();
177
178		// Get current state
179		let current_state = self
180			.get_state(extension_id)
181			.await
182			.ok_or_else(|| anyhow::anyhow!("Extension not found: {}", extension_id))?;
183
184		// Clone event for later use before moving it
185		let event_clone = event.clone();
186
187		// Determine new state based on event
188		let new_state = self.determine_next_state(current_state, event)?;
189
190		// Perform state transition (in real implementation, this would call extension)
191		self.perform_state_transition(extension_id, event_clone.clone(), new_state).await?;
192
193		let elapsed_ms = start.elapsed().as_millis() as u64;
194
195		// Record event
196		let record = LifecycleEventRecord {
197			extension_id:extension_id.to_string(),
198			event:event_clone,
199			previous_state:current_state,
200			new_state,
201			timestamp:std::time::SystemTime::now()
202				.duration_since(std::time::UNIX_EPOCH)
203				.map(|d| d.as_secs())
204				.unwrap_or(0),
205			duration_ms:elapsed_ms,
206			success:true,
207			error:None,
208		};
209
210		self.event_history.write().await.push(record);
211
212		debug!(
213			"Extension {} transitioned from {:?} to {:?} in {}ms",
214			extension_id, current_state, new_state, elapsed_ms
215		);
216
217		Ok(new_state)
218	}
219
220	/// Determine the next state based on current state and event
221	fn determine_next_state(&self, current_state:LifecycleState, event:LifecycleEvent) -> Result<LifecycleState> {
222		match (current_state, event.clone()) {
223			(LifecycleState::Created, LifecycleEvent::Initialize) => Ok(LifecycleState::Initializing),
224			(LifecycleState::Initializing, LifecycleEvent::Start) => Ok(LifecycleState::Running),
225			(LifecycleState::Running, LifecycleEvent::Suspend) => Ok(LifecycleState::Suspending),
226			(LifecycleState::Suspending, _) => Ok(LifecycleState::Suspended),
227			(LifecycleState::Suspended, LifecycleEvent::Resume) => Ok(LifecycleState::Running),
228			(LifecycleState::Running, LifecycleEvent::Stop) => Ok(LifecycleState::Stopping),
229			(LifecycleState::Stopping, _) => Ok(LifecycleState::Stopped),
230			(LifecycleState::Stopped | LifecycleState::Suspended, LifecycleEvent::Dispose) => {
231				Ok(LifecycleState::Disposing)
232			},
233			(LifecycleState::Disposing, _) => Ok(LifecycleState::Disposed),
234			(LifecycleState::Running, LifecycleEvent::Reload) => Ok(LifecycleState::Running),
235			_ => {
236				Err(anyhow::anyhow!(
237					"Invalid transition from {:?} with event {:?}",
238					current_state,
239					event
240				))
241			},
242		}
243	}
244
245	/// Perform actual state transition
246	async fn perform_state_transition(
247		&self,
248		extension_id:&str,
249		event:LifecycleEvent,
250		new_state:LifecycleState,
251	) -> Result<()> {
252		// In real implementation, this would:
253		// 1. Call the extension's lifecycle handler
254		// 2. Handle any errors
255		// 3. Rollback on failure
256
257		debug!(
258			"Performing state transition for extension {}: {:?} -> {:?}",
259			extension_id, event, new_state
260		);
261
262		// Update state
263		let mut handlers = self.handlers.write().await;
264		if let Some(handler) = handlers.get_mut(extension_id) {
265			handler.state = new_state;
266			handler.last_state_change = Some(
267				std::time::SystemTime::now()
268					.duration_since(std::time::UNIX_EPOCH)
269					.map(|d| d.as_secs())
270					.unwrap_or(0),
271			);
272		}
273
274		let mut states = self.states.write().await;
275		states.insert(extension_id.to_string(), new_state);
276
277		Ok(())
278	}
279
280	/// Trigger a lifecycle event for an extension
281	#[instrument(skip(self, extension_id, event))]
282	pub async fn trigger_event(&self, extension_id:&str, event:LifecycleEvent) -> Result<()> {
283		info!("Triggering lifecycle event for {}: {:?}", extension_id, event);
284
285		self.transition(extension_id, event).await?;
286
287		Ok(())
288	}
289
290	/// Get event history
291	pub async fn get_event_history(&self) -> Vec<LifecycleEventRecord> { self.event_history.read().await.clone() }
292
293	/// Get event history for a specific extension
294	pub async fn get_event_history_for_extension(&self, extension_id:&str) -> Vec<LifecycleEventRecord> {
295		self.event_history
296			.read()
297			.await
298			.iter()
299			.filter(|r| r.extension_id == extension_id)
300			.cloned()
301			.collect()
302	}
303
304	/// Get all registered extensions
305	pub async fn get_registered_extensions(&self) -> Vec<String> {
306		self.handlers.read().await.keys().cloned().collect()
307	}
308
309	/// Get extensions in a specific state
310	pub async fn get_extensions_in_state(&self, state:LifecycleState) -> Vec<String> {
311		self.states
312			.read()
313			.await
314			.iter()
315			.filter(|(_, s)| *s == &state)
316			.map(|(id, _)| id.clone())
317			.collect()
318	}
319}
320
321impl Default for LifecycleManager {
322	fn default() -> Self { Self::new() }
323}
324
325#[cfg(test)]
326mod tests {
327	use super::*;
328
329	#[test]
330	fn test_lifecycle_state() {
331		assert_eq!(LifecycleState::Created, LifecycleState::Created);
332		assert_eq!(LifecycleState::Running, LifecycleState::Running);
333		assert_ne!(LifecycleState::Created, LifecycleState::Running);
334	}
335
336	#[test]
337	fn test_lifecycle_event() {
338		assert_eq!(LifecycleEvent::Initialize, LifecycleEvent::Initialize);
339		assert_eq!(
340			LifecycleEvent::Custom("test".to_string()),
341			LifecycleEvent::Custom("test".to_string())
342		);
343	}
344
345	#[tokio::test]
346	async fn test_lifecycle_manager_registration() {
347		let manager = LifecycleManager::new();
348		let result = manager.register_extension("test.ext", LifecycleState::Created).await;
349
350		assert!(result.is_ok());
351		assert_eq!(manager.get_state("test.ext").await, Some(LifecycleState::Created));
352	}
353
354	#[tokio::test]
355	async fn test_state_transitions() {
356		let manager = LifecycleManager::new();
357		manager.register_extension("test.ext", LifecycleState::Created).await.unwrap();
358
359		// Initialize
360		let state = manager.transition("test.ext", LifecycleEvent::Initialize).await.unwrap();
361		assert_eq!(state, LifecycleState::Initializing);
362
363		// Start
364		let state = manager.transition("test.ext", LifecycleEvent::Start).await.unwrap();
365		assert_eq!(state, LifecycleState::Running);
366
367		// Stop
368		let state = manager.transition("test.ext", LifecycleEvent::Stop).await.unwrap();
369		assert_eq!(state, LifecycleState::Stopping);
370	}
371}