Quellcode für vyra_base.state.lifecycle_layer
"""
Lifecycle Layer - High-level API for module lifecycle management.
This layer controls module existence states:
- Startup and initialization
- Activation and deactivation
- Recovery from failures
- Controlled shutdown
Thread-safe wrapper around StateMachine for lifecycle operations.
"""
import logging
from typing import Optional, Dict, Any
from .state_machine import StateMachine, StateMachineConfig
from .state_types import LifecycleState
from .state_events import StateEvent, EventType
logger = logging.getLogger(__name__)
[Doku]
class LifecycleLayer:
"""
High-level API for lifecycle state management.
Provides intuitive methods for module lifecycle control:
- start() - Begin initialization
- activate() - Enter active state
- shutdown() - Controlled deactivation
- recover() - Recover from faults
Example:
>>> lifecycle = LifecycleLayer()
>>> lifecycle.start()
>>> lifecycle.complete_initialization()
>>> lifecycle.get_state()
'Active'
"""
[Doku]
def __init__(self, fsm: Optional[StateMachine] = None):
"""
Initialize lifecycle layer.
Args:
fsm: Existing StateMachine instance. Creates new if None.
"""
self.fsm = fsm if fsm is not None else StateMachine()
logger.info("LifecycleLayer initialized")
# -------------------------------------------------------------------------
# State Query
# -------------------------------------------------------------------------
[Doku]
def get_state(self) -> LifecycleState:
"""Get current lifecycle state."""
return self.fsm.get_lifecycle_state()
[Doku]
def get_state_name(self) -> str:
"""Get current lifecycle state as string."""
return self.get_state().value
# def is_uninitialized(self) -> bool:
# """Check if module is uninitialized."""
# return self.get_state() == LifecycleState.UNINITIALIZED
[Doku]
def is_initializing(self) -> bool:
"""Check if module is initializing."""
return self.get_state() == LifecycleState.INITIALIZING
[Doku]
def is_active(self) -> bool:
"""Check if module is active."""
return self.get_state() == LifecycleState.ACTIVE
[Doku]
def is_recovering(self) -> bool:
"""Check if module is recovering."""
return self.get_state() == LifecycleState.RECOVERING
[Doku]
def is_shutting_down(self) -> bool:
"""Check if module is shutting down."""
return self.get_state() == LifecycleState.SHUTTING_DOWN
[Doku]
def is_offline(self) -> bool:
"""Check if module is offline."""
return self.get_state() == LifecycleState.OFFLINE
[Doku]
def is_suspended(self) -> bool:
"""Check if module is suspended."""
return self.get_state() == LifecycleState.SUSPENDED
[Doku]
def can_accept_tasks(self) -> bool:
"""Check if module can accept operational tasks."""
return self.is_active() and self.fsm.is_healthy()
# -------------------------------------------------------------------------
# Lifecycle Control
# -------------------------------------------------------------------------
[Doku]
def start(self, metadata: Optional[Dict[str, Any]] = None) -> LifecycleState:
"""
Start module initialization.
Transitions: Offline → Initializing
Args:
metadata: Optional initialization parameters
Returns:
New lifecycle state
Raises:
InvalidTransitionError: If not in Offline state
"""
event = StateEvent(EventType.START, payload=metadata)
self.fsm.send_event(event)
logger.info("Module start initiated")
return self.get_state()
[Doku]
def complete_initialization(self, result: Optional[Dict[str, Any]] = None) -> LifecycleState:
"""
Mark initialization as successful.
Transitions: Initializing → Active
Args:
result: Optional initialization results
Returns:
New lifecycle state
"""
event = StateEvent(EventType.INIT_SUCCESS, payload=result)
self.fsm.send_event(event)
logger.info("Initialization completed successfully")
return self.get_state()
[Doku]
def fail_initialization(self, error: Optional[str] = None) -> LifecycleState:
"""
Mark initialization as failed.
Transitions: Initializing → Recovering
Args:
error: Error description
Returns:
New lifecycle state
"""
event = StateEvent(EventType.INIT_FAILURE, payload={"error": error})
self.fsm.send_event(event)
logger.error(f"Initialization failed: {error}")
return self.get_state()
[Doku]
def shutdown(self, reason: Optional[str] = None) -> LifecycleState:
"""
Begin controlled shutdown.
Transitions: Active → ShuttingDown
Args:
reason: Shutdown reason
Returns:
New lifecycle state
"""
event = StateEvent(EventType.SHUTDOWN, payload={"reason": reason})
self.fsm.send_event(event)
logger.info(f"Shutdown initiated: {reason}")
return self.get_state()
[Doku]
def complete_shutdown(self) -> LifecycleState:
"""
Complete shutdown process.
Transitions: ShuttingDown → Offline
Returns:
New lifecycle state
"""
event = StateEvent(EventType.FINISHED)
self.fsm.send_event(event)
logger.info("Shutdown completed")
return self.get_state()
[Doku]
def enter_suspend(self, reason: Optional[str] = None) -> LifecycleState:
"""
Suspend the module temporarily (e.g. for maintenance or updates).
Transitions: Active → Suspended
Args:
reason: Optional reason for suspension
Returns:
New lifecycle state
Raises:
InvalidTransitionError: If not in Active state
"""
event = StateEvent(EventType.SET_SUSPENDED, payload={"reason": reason})
self.fsm.send_event(event)
logger.info(f"Module suspended: {reason}")
return self.get_state()
[Doku]
def resume_from_suspend(self, info: Optional[dict] = None) -> LifecycleState:
"""
Resume module from Suspended state.
Transitions: Suspended → Active
Args:
info: Optional context about the resume
Returns:
New lifecycle state
Raises:
InvalidTransitionError: If not in Suspended state
"""
event = StateEvent(EventType.RESUME_SUSPENDED, payload=info)
self.fsm.send_event(event)
logger.info("Module resumed from suspend")
return self.get_state()
[Doku]
def enter_recovery(self, fault_info: Optional[Dict[str, Any]] = None) -> LifecycleState:
"""
Enter recovery mode due to fault.
Transitions: Active → Recovering
Args:
fault_info: Fault description and context
Returns:
New lifecycle state
"""
event = StateEvent(EventType.FAULT_DETECTED, payload=fault_info)
self.fsm.send_event(event)
logger.warning(f"Entering recovery mode: {fault_info}")
return self.get_state()
[Doku]
def complete_recovery(self, recovery_info: Optional[Dict[str, Any]] = None) -> LifecycleState:
"""
Complete recovery successfully.
Transitions: Recovering → Active
Args:
recovery_info: Recovery details
Returns:
New lifecycle state
"""
event = StateEvent(EventType.RECOVERY_SUCCESS, payload=recovery_info)
self.fsm.send_event(event)
logger.info("Recovery completed successfully")
return self.get_state()
[Doku]
def fail_recovery(self, error: Optional[str] = None) -> LifecycleState:
"""
Mark recovery as failed.
Transitions: Recovering → ShuttingDown
Args:
error: Recovery failure reason
Returns:
New lifecycle state
"""
event = StateEvent(EventType.RECOVERY_FAILED, payload={"error": error})
self.fsm.send_event(event)
logger.error(f"Recovery failed: {error}")
return self.get_state()
# -------------------------------------------------------------------------
# Callbacks
# -------------------------------------------------------------------------
[Doku]
def on_state_change(self, callback, priority: int = 0):
"""
Register callback for lifecycle state changes.
Args:
callback: Function(layer, old_state, new_state)
priority: Callback priority (higher = earlier execution)
"""
self.fsm.subscribe("lifecycle", callback, priority)
# -------------------------------------------------------------------------
# Diagnostics
# -------------------------------------------------------------------------
[Doku]
def get_info(self) -> Dict[str, Any]:
"""
Get lifecycle layer information.
Returns:
Dictionary with state and capability info
"""
return {
"state": self.get_state_name(),
"is_active": self.is_active(),
"can_accept_tasks": self.can_accept_tasks(),
"is_healthy": self.fsm.is_healthy(),
}
def __repr__(self) -> str:
"""String representation."""
return f"LifecycleLayer(state={self.get_state_name()})"