1use serde::{Deserialize, Serialize};
8use sklears_core::error::{Result as SklResult, SklearsError};
9use std::collections::{HashMap, HashSet};
10use std::time::{Duration, SystemTime};
11
12#[derive(Debug)]
17pub struct LifecycleManager {
18 component_states: HashMap<String, ComponentLifecycleState>,
20 dependencies: HashMap<String, Vec<String>>,
22 listeners: HashMap<LifecycleEvent, Vec<String>>,
24 initialization_order: Vec<String>,
26 config: LifecycleConfig,
28 metrics: LifecycleMetrics,
30}
31
32impl LifecycleManager {
33 #[must_use]
35 pub fn new() -> Self {
36 Self {
37 component_states: HashMap::new(),
38 dependencies: HashMap::new(),
39 listeners: HashMap::new(),
40 initialization_order: Vec::new(),
41 config: LifecycleConfig::default(),
42 metrics: LifecycleMetrics::new(),
43 }
44 }
45
46 pub fn register_component(
48 &mut self,
49 component_id: &str,
50 dependencies: Vec<String>,
51 ) -> SklResult<()> {
52 if self.component_states.contains_key(component_id) {
53 return Err(SklearsError::InvalidInput(format!(
54 "Component {component_id} already registered"
55 )));
56 }
57
58 self.component_states
59 .insert(component_id.to_string(), ComponentLifecycleState::Created);
60 self.dependencies
61 .insert(component_id.to_string(), dependencies);
62 self.metrics.total_components += 1;
63
64 self.initialization_order.clear();
66
67 Ok(())
68 }
69
70 pub fn unregister_component(&mut self, component_id: &str) -> SklResult<()> {
72 if let Some(state) = self.component_states.get(component_id) {
73 if matches!(state, ComponentLifecycleState::Running) {
74 return Err(SklearsError::InvalidInput(format!(
75 "Cannot unregister running component {component_id}"
76 )));
77 }
78 }
79
80 self.component_states.remove(component_id);
81 self.dependencies.remove(component_id);
82 self.initialization_order.retain(|id| id != component_id);
83 self.metrics.total_components = self.metrics.total_components.saturating_sub(1);
84
85 Ok(())
86 }
87
88 pub fn set_component_state(
90 &mut self,
91 component_id: &str,
92 state: ComponentLifecycleState,
93 ) -> SklResult<()> {
94 if !self.component_states.contains_key(component_id) {
95 return Err(SklearsError::InvalidInput(format!(
96 "Component {component_id} not registered"
97 )));
98 }
99
100 let old_state = self.component_states.get(component_id).unwrap().clone();
101
102 if !self.is_valid_transition(&old_state, &state) {
104 return Err(SklearsError::InvalidInput(format!(
105 "Invalid state transition from {old_state:?} to {state:?}"
106 )));
107 }
108
109 self.component_states
110 .insert(component_id.to_string(), state.clone());
111
112 match &state {
114 ComponentLifecycleState::Ready => self.metrics.ready_components += 1,
115 ComponentLifecycleState::Running => {
116 self.metrics.running_components += 1;
117 self.metrics.ready_components = self.metrics.ready_components.saturating_sub(1);
118 }
119 ComponentLifecycleState::Stopped => {
120 self.metrics.running_components = self.metrics.running_components.saturating_sub(1);
121 }
122 ComponentLifecycleState::Error(_) => self.metrics.failed_components += 1,
123 _ => {}
124 }
125
126 self.notify_lifecycle_event(LifecycleEvent::StateChanged {
128 component_id: component_id.to_string(),
129 old_state,
130 new_state: state,
131 })?;
132
133 Ok(())
134 }
135
136 #[must_use]
138 pub fn get_component_state(&self, component_id: &str) -> Option<&ComponentLifecycleState> {
139 self.component_states.get(component_id)
140 }
141
142 pub fn initialize_all_components(&mut self) -> SklResult<InitializationResult> {
144 let start_time = SystemTime::now();
145 let mut result = InitializationResult {
146 total_components: self.component_states.len(),
147 successful_initializations: 0,
148 failed_initializations: 0,
149 initialization_order: Vec::new(),
150 duration: Duration::from_secs(0),
151 errors: Vec::new(),
152 };
153
154 if self.initialization_order.is_empty() {
156 self.initialization_order = self.calculate_initialization_order()?;
157 }
158
159 result.initialization_order = self.initialization_order.clone();
160
161 let initialization_order = self.initialization_order.clone();
163 for component_id in &initialization_order {
164 match self.initialize_component(component_id) {
165 Ok(()) => {
166 result.successful_initializations += 1;
167 self.notify_lifecycle_event(LifecycleEvent::ComponentInitialized {
168 component_id: component_id.clone(),
169 })?;
170 }
171 Err(e) => {
172 result.failed_initializations += 1;
173 result
174 .errors
175 .push(format!("Failed to initialize {component_id}: {e}"));
176
177 if self.config.fail_fast_initialization {
178 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
179 return Ok(result);
180 }
181 }
182 }
183 }
184
185 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
186 self.metrics.last_initialization_time = result.duration;
187
188 Ok(result)
189 }
190
191 pub fn initialize_component(&mut self, component_id: &str) -> SklResult<()> {
193 let current_state = self.component_states.get(component_id).ok_or_else(|| {
195 SklearsError::InvalidInput(format!("Component {component_id} not found"))
196 })?;
197
198 if matches!(
200 current_state,
201 ComponentLifecycleState::Ready | ComponentLifecycleState::Running
202 ) {
203 return Ok(());
204 }
205
206 if let Some(deps) = self.dependencies.get(component_id) {
208 for dep in deps {
209 let dep_state = self.component_states.get(dep).ok_or_else(|| {
210 SklearsError::InvalidInput(format!("Dependency {dep} not found"))
211 })?;
212
213 if !matches!(
214 dep_state,
215 ComponentLifecycleState::Ready | ComponentLifecycleState::Running
216 ) {
217 return Err(SklearsError::InvalidInput(format!(
218 "Dependency {dep} not ready for {component_id}"
219 )));
220 }
221 }
222 }
223
224 self.set_component_state(component_id, ComponentLifecycleState::Initializing)?;
226
227 std::thread::sleep(Duration::from_millis(10)); self.set_component_state(component_id, ComponentLifecycleState::Ready)?;
232
233 Ok(())
234 }
235
236 pub fn shutdown_all_components(&mut self) -> SklResult<ShutdownResult> {
238 let start_time = SystemTime::now();
239 let mut result = ShutdownResult {
240 total_components: self.component_states.len(),
241 successful_shutdowns: 0,
242 failed_shutdowns: 0,
243 shutdown_order: Vec::new(),
244 duration: Duration::from_secs(0),
245 errors: Vec::new(),
246 };
247
248 let shutdown_order: Vec<String> = self.initialization_order.iter().rev().cloned().collect();
250 result.shutdown_order = shutdown_order.clone();
251
252 for component_id in &shutdown_order {
254 match self.shutdown_component(component_id) {
255 Ok(()) => {
256 result.successful_shutdowns += 1;
257 self.notify_lifecycle_event(LifecycleEvent::ComponentShutdown {
258 component_id: component_id.clone(),
259 })?;
260 }
261 Err(e) => {
262 result.failed_shutdowns += 1;
263 result
264 .errors
265 .push(format!("Failed to shutdown {component_id}: {e}"));
266 }
267 }
268 }
269
270 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
271 self.metrics.last_shutdown_time = result.duration;
272
273 Ok(result)
274 }
275
276 pub fn shutdown_component(&mut self, component_id: &str) -> SklResult<()> {
278 let current_state = self.component_states.get(component_id).ok_or_else(|| {
279 SklearsError::InvalidInput(format!("Component {component_id} not found"))
280 })?;
281
282 if matches!(current_state, ComponentLifecycleState::Stopped) {
283 return Ok(());
284 }
285
286 self.set_component_state(component_id, ComponentLifecycleState::Stopping)?;
288
289 std::thread::sleep(Duration::from_millis(5)); self.set_component_state(component_id, ComponentLifecycleState::Stopped)?;
294
295 Ok(())
296 }
297
298 pub fn add_listener(&mut self, event: LifecycleEvent, listener_id: &str) {
300 self.listeners
301 .entry(event)
302 .or_default()
303 .push(listener_id.to_string());
304 }
305
306 pub fn remove_listener(&mut self, event: &LifecycleEvent, listener_id: &str) {
308 if let Some(listeners) = self.listeners.get_mut(event) {
309 listeners.retain(|id| id != listener_id);
310 }
311 }
312
313 #[must_use]
315 pub fn get_metrics(&self) -> &LifecycleMetrics {
316 &self.metrics
317 }
318
319 #[must_use]
321 pub fn get_all_states(&self) -> &HashMap<String, ComponentLifecycleState> {
322 &self.component_states
323 }
324
325 #[must_use]
327 pub fn all_components_in_state(&self, state: &ComponentLifecycleState) -> bool {
328 self.component_states.values().all(|s| s == state)
329 }
330
331 #[must_use]
333 pub fn get_components_in_state(&self, state: &ComponentLifecycleState) -> Vec<String> {
334 self.component_states
335 .iter()
336 .filter_map(|(id, s)| if s == state { Some(id.clone()) } else { None })
337 .collect()
338 }
339
340 fn calculate_initialization_order(&self) -> SklResult<Vec<String>> {
341 let mut order = Vec::new();
342 let mut visited = HashSet::new();
343 let mut visiting = HashSet::new();
344
345 for component_id in self.component_states.keys() {
346 if !visited.contains(component_id) {
347 self.topological_sort(component_id, &mut visited, &mut visiting, &mut order)?;
348 }
349 }
350
351 Ok(order)
352 }
353
354 fn topological_sort(
355 &self,
356 component_id: &str,
357 visited: &mut HashSet<String>,
358 visiting: &mut HashSet<String>,
359 order: &mut Vec<String>,
360 ) -> SklResult<()> {
361 if visiting.contains(component_id) {
362 return Err(SklearsError::InvalidInput(format!(
363 "Circular dependency detected involving {component_id}"
364 )));
365 }
366
367 if visited.contains(component_id) {
368 return Ok(());
369 }
370
371 visiting.insert(component_id.to_string());
372
373 if let Some(deps) = self.dependencies.get(component_id) {
374 for dep in deps {
375 self.topological_sort(dep, visited, visiting, order)?;
376 }
377 }
378
379 visiting.remove(component_id);
380 visited.insert(component_id.to_string());
381 order.push(component_id.to_string());
382
383 Ok(())
384 }
385
386 fn is_valid_transition(
387 &self,
388 from: &ComponentLifecycleState,
389 to: &ComponentLifecycleState,
390 ) -> bool {
391 use ComponentLifecycleState::{
392 Created, Error, Initializing, Paused, Ready, Running, Stopped, Stopping,
393 };
394
395 match (from, to) {
396 (Created, Initializing) => true,
397 (Initializing, Ready) => true,
398 (Initializing, Error(_)) => true,
399 (Ready, Running) => true,
400 (Ready, Paused) => true,
401 (Ready, Stopping) => true,
402 (Running, Paused) => true,
403 (Running, Stopping) => true,
404 (Paused, Running) => true,
405 (Paused, Stopping) => true,
406 (Stopping, Stopped) => true,
407 (Error(_), Initializing) => true, _ => false,
409 }
410 }
411
412 fn notify_lifecycle_event(&mut self, event: LifecycleEvent) -> SklResult<()> {
413 if let Some(listeners) = self.listeners.get(&event) {
414 for listener in listeners {
415 self.metrics.total_notifications += 1;
418 }
419 }
420 Ok(())
421 }
422}
423
424#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
426pub enum ComponentLifecycleState {
427 Created,
429 Initializing,
431 Ready,
433 Running,
435 Paused,
437 Stopping,
439 Stopped,
441 Error(String),
443}
444
445#[derive(Debug, Clone, PartialEq, Eq, Hash)]
447pub enum LifecycleEvent {
448 StateChanged {
449 component_id: String,
450 old_state: ComponentLifecycleState,
451 new_state: ComponentLifecycleState,
452 },
453 ComponentInitialized { component_id: String },
455 ComponentShutdown { component_id: String },
457 AllComponentsInitialized,
459 AllComponentsShutdown,
461}
462
463#[derive(Debug, Clone)]
465pub struct LifecycleConfig {
466 pub fail_fast_initialization: bool,
468 pub initialization_timeout: Duration,
470 pub shutdown_timeout: Duration,
472 pub auto_restart_on_failure: bool,
474 pub max_restart_attempts: u32,
476}
477
478impl Default for LifecycleConfig {
479 fn default() -> Self {
480 Self {
481 fail_fast_initialization: true,
482 initialization_timeout: Duration::from_secs(30),
483 shutdown_timeout: Duration::from_secs(10),
484 auto_restart_on_failure: false,
485 max_restart_attempts: 3,
486 }
487 }
488}
489
490#[derive(Debug, Clone)]
492pub struct LifecycleMetrics {
493 pub total_components: usize,
495 pub ready_components: usize,
497 pub running_components: usize,
499 pub failed_components: usize,
501 pub last_initialization_time: Duration,
503 pub last_shutdown_time: Duration,
505 pub total_notifications: u64,
507}
508
509impl Default for LifecycleMetrics {
510 fn default() -> Self {
511 Self::new()
512 }
513}
514
515impl LifecycleMetrics {
516 #[must_use]
517 pub fn new() -> Self {
518 Self {
519 total_components: 0,
520 ready_components: 0,
521 running_components: 0,
522 failed_components: 0,
523 last_initialization_time: Duration::from_secs(0),
524 last_shutdown_time: Duration::from_secs(0),
525 total_notifications: 0,
526 }
527 }
528}
529
530#[derive(Debug, Clone)]
532pub struct InitializationResult {
533 pub total_components: usize,
535 pub successful_initializations: usize,
537 pub failed_initializations: usize,
539 pub initialization_order: Vec<String>,
541 pub duration: Duration,
543 pub errors: Vec<String>,
545}
546
547#[derive(Debug, Clone)]
549pub struct ShutdownResult {
550 pub total_components: usize,
552 pub successful_shutdowns: usize,
554 pub failed_shutdowns: usize,
556 pub shutdown_order: Vec<String>,
558 pub duration: Duration,
560 pub errors: Vec<String>,
562}
563
564impl Default for LifecycleManager {
565 fn default() -> Self {
566 Self::new()
567 }
568}
569
570#[allow(non_snake_case)]
571#[cfg(test)]
572mod tests {
573 use super::*;
574
575 #[test]
576 fn test_lifecycle_manager_creation() {
577 let manager = LifecycleManager::new();
578 assert_eq!(manager.get_metrics().total_components, 0);
579 }
580
581 #[test]
582 fn test_component_registration() {
583 let mut manager = LifecycleManager::new();
584
585 let result = manager.register_component("component_a", vec![]);
586 assert!(result.is_ok());
587 assert_eq!(manager.get_metrics().total_components, 1);
588
589 let state = manager.get_component_state("component_a");
590 assert_eq!(state, Some(&ComponentLifecycleState::Created));
591 }
592
593 #[test]
594 fn test_state_transitions() {
595 let mut manager = LifecycleManager::new();
596 manager.register_component("component_a", vec![]).unwrap();
597
598 let result =
600 manager.set_component_state("component_a", ComponentLifecycleState::Initializing);
601 assert!(result.is_ok());
602
603 let result = manager.set_component_state("component_a", ComponentLifecycleState::Stopped);
605 assert!(result.is_err());
606 }
607
608 #[test]
609 fn test_dependency_resolution() {
610 let mut manager = LifecycleManager::new();
611
612 manager.register_component("component_a", vec![]).unwrap();
613 manager
614 .register_component("component_b", vec!["component_a".to_string()])
615 .unwrap();
616
617 let order = manager.calculate_initialization_order().unwrap();
618 assert_eq!(order, vec!["component_a", "component_b"]);
619 }
620
621 #[test]
622 fn test_circular_dependency_detection() {
623 let mut manager = LifecycleManager::new();
624
625 manager
626 .register_component("component_a", vec!["component_b".to_string()])
627 .unwrap();
628 manager
629 .register_component("component_b", vec!["component_a".to_string()])
630 .unwrap();
631
632 let result = manager.calculate_initialization_order();
633 assert!(result.is_err());
634 }
635
636 #[test]
637 fn test_component_initialization() {
638 let mut manager = LifecycleManager::new();
639 manager.register_component("component_a", vec![]).unwrap();
640
641 let result = manager.initialize_component("component_a");
642 assert!(result.is_ok());
643
644 let state = manager.get_component_state("component_a");
645 assert_eq!(state, Some(&ComponentLifecycleState::Ready));
646 }
647
648 #[test]
649 fn test_full_lifecycle() {
650 let mut manager = LifecycleManager::new();
651
652 manager.register_component("component_a", vec![]).unwrap();
653 manager
654 .register_component("component_b", vec!["component_a".to_string()])
655 .unwrap();
656
657 let init_result = manager.initialize_all_components().unwrap();
658 assert_eq!(init_result.successful_initializations, 2);
659 assert_eq!(init_result.failed_initializations, 0);
660
661 let shutdown_result = manager.shutdown_all_components().unwrap();
662 assert_eq!(shutdown_result.successful_shutdowns, 2);
663 assert_eq!(shutdown_result.failed_shutdowns, 0);
664 }
665}