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
101 .component_states
102 .get(component_id)
103 .cloned()
104 .unwrap_or(ComponentLifecycleState::Created);
105
106 if !self.is_valid_transition(&old_state, &state) {
108 return Err(SklearsError::InvalidInput(format!(
109 "Invalid state transition from {old_state:?} to {state:?}"
110 )));
111 }
112
113 self.component_states
114 .insert(component_id.to_string(), state.clone());
115
116 match &state {
118 ComponentLifecycleState::Ready => self.metrics.ready_components += 1,
119 ComponentLifecycleState::Running => {
120 self.metrics.running_components += 1;
121 self.metrics.ready_components = self.metrics.ready_components.saturating_sub(1);
122 }
123 ComponentLifecycleState::Stopped => {
124 self.metrics.running_components = self.metrics.running_components.saturating_sub(1);
125 }
126 ComponentLifecycleState::Error(_) => self.metrics.failed_components += 1,
127 _ => {}
128 }
129
130 self.notify_lifecycle_event(LifecycleEvent::StateChanged {
132 component_id: component_id.to_string(),
133 old_state,
134 new_state: state,
135 })?;
136
137 Ok(())
138 }
139
140 #[must_use]
142 pub fn get_component_state(&self, component_id: &str) -> Option<&ComponentLifecycleState> {
143 self.component_states.get(component_id)
144 }
145
146 pub fn initialize_all_components(&mut self) -> SklResult<InitializationResult> {
148 let start_time = SystemTime::now();
149 let mut result = InitializationResult {
150 total_components: self.component_states.len(),
151 successful_initializations: 0,
152 failed_initializations: 0,
153 initialization_order: Vec::new(),
154 duration: Duration::from_secs(0),
155 errors: Vec::new(),
156 };
157
158 if self.initialization_order.is_empty() {
160 self.initialization_order = self.calculate_initialization_order()?;
161 }
162
163 result.initialization_order = self.initialization_order.clone();
164
165 let initialization_order = self.initialization_order.clone();
167 for component_id in &initialization_order {
168 match self.initialize_component(component_id) {
169 Ok(()) => {
170 result.successful_initializations += 1;
171 self.notify_lifecycle_event(LifecycleEvent::ComponentInitialized {
172 component_id: component_id.clone(),
173 })?;
174 }
175 Err(e) => {
176 result.failed_initializations += 1;
177 result
178 .errors
179 .push(format!("Failed to initialize {component_id}: {e}"));
180
181 if self.config.fail_fast_initialization {
182 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
183 return Ok(result);
184 }
185 }
186 }
187 }
188
189 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
190 self.metrics.last_initialization_time = result.duration;
191
192 Ok(result)
193 }
194
195 pub fn initialize_component(&mut self, component_id: &str) -> SklResult<()> {
197 let current_state = self.component_states.get(component_id).ok_or_else(|| {
199 SklearsError::InvalidInput(format!("Component {component_id} not found"))
200 })?;
201
202 if matches!(
204 current_state,
205 ComponentLifecycleState::Ready | ComponentLifecycleState::Running
206 ) {
207 return Ok(());
208 }
209
210 if let Some(deps) = self.dependencies.get(component_id) {
212 for dep in deps {
213 let dep_state = self.component_states.get(dep).ok_or_else(|| {
214 SklearsError::InvalidInput(format!("Dependency {dep} not found"))
215 })?;
216
217 if !matches!(
218 dep_state,
219 ComponentLifecycleState::Ready | ComponentLifecycleState::Running
220 ) {
221 return Err(SklearsError::InvalidInput(format!(
222 "Dependency {dep} not ready for {component_id}"
223 )));
224 }
225 }
226 }
227
228 self.set_component_state(component_id, ComponentLifecycleState::Initializing)?;
230
231 std::thread::sleep(Duration::from_millis(10)); self.set_component_state(component_id, ComponentLifecycleState::Ready)?;
236
237 Ok(())
238 }
239
240 pub fn shutdown_all_components(&mut self) -> SklResult<ShutdownResult> {
242 let start_time = SystemTime::now();
243 let mut result = ShutdownResult {
244 total_components: self.component_states.len(),
245 successful_shutdowns: 0,
246 failed_shutdowns: 0,
247 shutdown_order: Vec::new(),
248 duration: Duration::from_secs(0),
249 errors: Vec::new(),
250 };
251
252 let shutdown_order: Vec<String> = self.initialization_order.iter().rev().cloned().collect();
254 result.shutdown_order = shutdown_order.clone();
255
256 for component_id in &shutdown_order {
258 match self.shutdown_component(component_id) {
259 Ok(()) => {
260 result.successful_shutdowns += 1;
261 self.notify_lifecycle_event(LifecycleEvent::ComponentShutdown {
262 component_id: component_id.clone(),
263 })?;
264 }
265 Err(e) => {
266 result.failed_shutdowns += 1;
267 result
268 .errors
269 .push(format!("Failed to shutdown {component_id}: {e}"));
270 }
271 }
272 }
273
274 result.duration = start_time.elapsed().unwrap_or(Duration::from_secs(0));
275 self.metrics.last_shutdown_time = result.duration;
276
277 Ok(result)
278 }
279
280 pub fn shutdown_component(&mut self, component_id: &str) -> SklResult<()> {
282 let current_state = self.component_states.get(component_id).ok_or_else(|| {
283 SklearsError::InvalidInput(format!("Component {component_id} not found"))
284 })?;
285
286 if matches!(current_state, ComponentLifecycleState::Stopped) {
287 return Ok(());
288 }
289
290 self.set_component_state(component_id, ComponentLifecycleState::Stopping)?;
292
293 std::thread::sleep(Duration::from_millis(5)); self.set_component_state(component_id, ComponentLifecycleState::Stopped)?;
298
299 Ok(())
300 }
301
302 pub fn add_listener(&mut self, event: LifecycleEvent, listener_id: &str) {
304 self.listeners
305 .entry(event)
306 .or_default()
307 .push(listener_id.to_string());
308 }
309
310 pub fn remove_listener(&mut self, event: &LifecycleEvent, listener_id: &str) {
312 if let Some(listeners) = self.listeners.get_mut(event) {
313 listeners.retain(|id| id != listener_id);
314 }
315 }
316
317 #[must_use]
319 pub fn get_metrics(&self) -> &LifecycleMetrics {
320 &self.metrics
321 }
322
323 #[must_use]
325 pub fn get_all_states(&self) -> &HashMap<String, ComponentLifecycleState> {
326 &self.component_states
327 }
328
329 #[must_use]
331 pub fn all_components_in_state(&self, state: &ComponentLifecycleState) -> bool {
332 self.component_states.values().all(|s| s == state)
333 }
334
335 #[must_use]
337 pub fn get_components_in_state(&self, state: &ComponentLifecycleState) -> Vec<String> {
338 self.component_states
339 .iter()
340 .filter_map(|(id, s)| if s == state { Some(id.clone()) } else { None })
341 .collect()
342 }
343
344 fn calculate_initialization_order(&self) -> SklResult<Vec<String>> {
345 let mut order = Vec::new();
346 let mut visited = HashSet::new();
347 let mut visiting = HashSet::new();
348
349 for component_id in self.component_states.keys() {
350 if !visited.contains(component_id) {
351 self.topological_sort(component_id, &mut visited, &mut visiting, &mut order)?;
352 }
353 }
354
355 Ok(order)
356 }
357
358 fn topological_sort(
359 &self,
360 component_id: &str,
361 visited: &mut HashSet<String>,
362 visiting: &mut HashSet<String>,
363 order: &mut Vec<String>,
364 ) -> SklResult<()> {
365 if visiting.contains(component_id) {
366 return Err(SklearsError::InvalidInput(format!(
367 "Circular dependency detected involving {component_id}"
368 )));
369 }
370
371 if visited.contains(component_id) {
372 return Ok(());
373 }
374
375 visiting.insert(component_id.to_string());
376
377 if let Some(deps) = self.dependencies.get(component_id) {
378 for dep in deps {
379 self.topological_sort(dep, visited, visiting, order)?;
380 }
381 }
382
383 visiting.remove(component_id);
384 visited.insert(component_id.to_string());
385 order.push(component_id.to_string());
386
387 Ok(())
388 }
389
390 fn is_valid_transition(
391 &self,
392 from: &ComponentLifecycleState,
393 to: &ComponentLifecycleState,
394 ) -> bool {
395 use ComponentLifecycleState::{
396 Created, Error, Initializing, Paused, Ready, Running, Stopped, Stopping,
397 };
398
399 match (from, to) {
400 (Created, Initializing) => true,
401 (Initializing, Ready) => true,
402 (Initializing, Error(_)) => true,
403 (Ready, Running) => true,
404 (Ready, Paused) => true,
405 (Ready, Stopping) => true,
406 (Running, Paused) => true,
407 (Running, Stopping) => true,
408 (Paused, Running) => true,
409 (Paused, Stopping) => true,
410 (Stopping, Stopped) => true,
411 (Error(_), Initializing) => true, _ => false,
413 }
414 }
415
416 fn notify_lifecycle_event(&mut self, event: LifecycleEvent) -> SklResult<()> {
417 if let Some(listeners) = self.listeners.get(&event) {
418 for listener in listeners {
419 self.metrics.total_notifications += 1;
422 }
423 }
424 Ok(())
425 }
426}
427
428#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
430pub enum ComponentLifecycleState {
431 Created,
433 Initializing,
435 Ready,
437 Running,
439 Paused,
441 Stopping,
443 Stopped,
445 Error(String),
447}
448
449#[derive(Debug, Clone, PartialEq, Eq, Hash)]
451pub enum LifecycleEvent {
452 StateChanged {
453 component_id: String,
454 old_state: ComponentLifecycleState,
455 new_state: ComponentLifecycleState,
456 },
457 ComponentInitialized { component_id: String },
459 ComponentShutdown { component_id: String },
461 AllComponentsInitialized,
463 AllComponentsShutdown,
465}
466
467#[derive(Debug, Clone)]
469pub struct LifecycleConfig {
470 pub fail_fast_initialization: bool,
472 pub initialization_timeout: Duration,
474 pub shutdown_timeout: Duration,
476 pub auto_restart_on_failure: bool,
478 pub max_restart_attempts: u32,
480}
481
482impl Default for LifecycleConfig {
483 fn default() -> Self {
484 Self {
485 fail_fast_initialization: true,
486 initialization_timeout: Duration::from_secs(30),
487 shutdown_timeout: Duration::from_secs(10),
488 auto_restart_on_failure: false,
489 max_restart_attempts: 3,
490 }
491 }
492}
493
494#[derive(Debug, Clone)]
496pub struct LifecycleMetrics {
497 pub total_components: usize,
499 pub ready_components: usize,
501 pub running_components: usize,
503 pub failed_components: usize,
505 pub last_initialization_time: Duration,
507 pub last_shutdown_time: Duration,
509 pub total_notifications: u64,
511}
512
513impl Default for LifecycleMetrics {
514 fn default() -> Self {
515 Self::new()
516 }
517}
518
519impl LifecycleMetrics {
520 #[must_use]
521 pub fn new() -> Self {
522 Self {
523 total_components: 0,
524 ready_components: 0,
525 running_components: 0,
526 failed_components: 0,
527 last_initialization_time: Duration::from_secs(0),
528 last_shutdown_time: Duration::from_secs(0),
529 total_notifications: 0,
530 }
531 }
532}
533
534#[derive(Debug, Clone)]
536pub struct InitializationResult {
537 pub total_components: usize,
539 pub successful_initializations: usize,
541 pub failed_initializations: usize,
543 pub initialization_order: Vec<String>,
545 pub duration: Duration,
547 pub errors: Vec<String>,
549}
550
551#[derive(Debug, Clone)]
553pub struct ShutdownResult {
554 pub total_components: usize,
556 pub successful_shutdowns: usize,
558 pub failed_shutdowns: usize,
560 pub shutdown_order: Vec<String>,
562 pub duration: Duration,
564 pub errors: Vec<String>,
566}
567
568impl Default for LifecycleManager {
569 fn default() -> Self {
570 Self::new()
571 }
572}
573
574#[allow(non_snake_case)]
575#[cfg(test)]
576mod tests {
577 use super::*;
578
579 #[test]
580 fn test_lifecycle_manager_creation() {
581 let manager = LifecycleManager::new();
582 assert_eq!(manager.get_metrics().total_components, 0);
583 }
584
585 #[test]
586 fn test_component_registration() {
587 let mut manager = LifecycleManager::new();
588
589 let result = manager.register_component("component_a", vec![]);
590 assert!(result.is_ok());
591 assert_eq!(manager.get_metrics().total_components, 1);
592
593 let state = manager.get_component_state("component_a");
594 assert_eq!(state, Some(&ComponentLifecycleState::Created));
595 }
596
597 #[test]
598 fn test_state_transitions() {
599 let mut manager = LifecycleManager::new();
600 manager
601 .register_component("component_a", vec![])
602 .unwrap_or_default();
603
604 let result =
606 manager.set_component_state("component_a", ComponentLifecycleState::Initializing);
607 assert!(result.is_ok());
608
609 let result = manager.set_component_state("component_a", ComponentLifecycleState::Stopped);
611 assert!(result.is_err());
612 }
613
614 #[test]
615 fn test_dependency_resolution() {
616 let mut manager = LifecycleManager::new();
617
618 manager
619 .register_component("component_a", vec![])
620 .unwrap_or_default();
621 manager
622 .register_component("component_b", vec!["component_a".to_string()])
623 .unwrap_or_default();
624
625 let order = manager.calculate_initialization_order().unwrap_or_default();
626 assert_eq!(order, vec!["component_a", "component_b"]);
627 }
628
629 #[test]
630 fn test_circular_dependency_detection() {
631 let mut manager = LifecycleManager::new();
632
633 manager
634 .register_component("component_a", vec!["component_b".to_string()])
635 .unwrap_or_default();
636 manager
637 .register_component("component_b", vec!["component_a".to_string()])
638 .unwrap_or_default();
639
640 let result = manager.calculate_initialization_order();
641 assert!(result.is_err());
642 }
643
644 #[test]
645 fn test_component_initialization() {
646 let mut manager = LifecycleManager::new();
647 manager
648 .register_component("component_a", vec![])
649 .unwrap_or_default();
650
651 let result = manager.initialize_component("component_a");
652 assert!(result.is_ok());
653
654 let state = manager.get_component_state("component_a");
655 assert_eq!(state, Some(&ComponentLifecycleState::Ready));
656 }
657
658 #[test]
659 fn test_full_lifecycle() {
660 let mut manager = LifecycleManager::new();
661
662 manager
663 .register_component("component_a", vec![])
664 .unwrap_or_default();
665 manager
666 .register_component("component_b", vec!["component_a".to_string()])
667 .unwrap_or_default();
668
669 let init_result = manager
670 .initialize_all_components()
671 .expect("operation should succeed");
672 assert_eq!(init_result.successful_initializations, 2);
673 assert_eq!(init_result.failed_initializations, 0);
674
675 let shutdown_result = manager
676 .shutdown_all_components()
677 .expect("operation should succeed");
678 assert_eq!(shutdown_result.successful_shutdowns, 2);
679 assert_eq!(shutdown_result.failed_shutdowns, 0);
680 }
681}