Skip to main content

appcore_core/
lifecycle.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: lifecycle.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/05/29 20:47:35 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/07/24 16:07:49 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11//! Bounded/thread-safe runtime lifecycle contract built on top of StateMachine.
12
13use crate::error::{RuntimeError, RuntimeResult};
14use crate::ids::{EventName, StateName};
15use crate::state::{StateMachine, StateTransition};
16use parking_lot::Mutex;
17
18// NOTA: Estados de lifecycle estendidos como checking-identity, discovering-peers, readonly e syncing
19// foram adiados para a versão v0.7 para manter a estabilidade do contrato de transições por enquanto.
20/// Stable process lifecycle state.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum RuntimeLifecycleState {
23    /// Runtime process is booting.
24    Booting,
25    /// Runtime configuration is being loaded.
26    LoadingConfig,
27    /// Security configuration is being checked.
28    CheckingSecurity,
29    /// Storage boundaries are being opened.
30    OpeningStorage,
31    /// Runtime API boundaries are starting.
32    StartingApi,
33    /// Runtime is accepting declared work.
34    Running,
35    /// Runtime remains available with reduced guarantees.
36    Degraded,
37    /// Runtime accepts only explicitly permitted operations.
38    Restricted,
39    /// Runtime is performing graceful shutdown.
40    ShuttingDown,
41    /// Runtime has stopped.
42    Stopped,
43}
44
45/// Event accepted by the Runtime process lifecycle.
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum RuntimeLifecycleEvent {
48    /// Configuration loading completed.
49    ConfigLoaded,
50    /// Security checks completed.
51    SecurityChecked,
52    /// Storage initialization completed.
53    StorageOpened,
54    /// API startup completed.
55    ApiStarted,
56    /// A degradable failure was observed.
57    DegradedDetected,
58    /// A restriction policy was activated.
59    RestrictedDetected,
60    /// Graceful shutdown was requested.
61    ShutdownRequested,
62    /// Graceful shutdown completed.
63    ShutdownCompleted,
64    /// A degraded or restricted condition recovered.
65    RecoveryCompleted,
66}
67
68/// Thread-safe state machine for the Runtime process lifecycle.
69#[derive(Debug)]
70pub struct RuntimeLifecycle {
71    machine: Mutex<StateMachine>,
72}
73
74impl Clone for RuntimeLifecycle {
75    fn clone(&self) -> Self {
76        let guard = self.machine.lock();
77        Self {
78            machine: Mutex::new(guard.clone()),
79        }
80    }
81}
82
83impl RuntimeLifecycleState {
84    fn as_state_name(self) -> StateName {
85        // appcore-norm: allow(clippy::unwrap_used) reason: enum mapping uses validated static state names
86        StateName::new(match self {
87            RuntimeLifecycleState::Booting => "Booting",
88            RuntimeLifecycleState::LoadingConfig => "LoadingConfig",
89            RuntimeLifecycleState::CheckingSecurity => "CheckingSecurity",
90            RuntimeLifecycleState::OpeningStorage => "OpeningStorage",
91            RuntimeLifecycleState::StartingApi => "StartingApi",
92            RuntimeLifecycleState::Running => "Running",
93            RuntimeLifecycleState::Degraded => "Degraded",
94            RuntimeLifecycleState::Restricted => "Restricted",
95            RuntimeLifecycleState::ShuttingDown => "ShuttingDown",
96            RuntimeLifecycleState::Stopped => "Stopped",
97        })
98        .unwrap()
99    }
100
101    fn from_state_name(state: &StateName) -> RuntimeResult<Self> {
102        match state.as_str() {
103            "Booting" => Ok(Self::Booting),
104            "LoadingConfig" => Ok(Self::LoadingConfig),
105            "CheckingSecurity" => Ok(Self::CheckingSecurity),
106            "OpeningStorage" => Ok(Self::OpeningStorage),
107            "StartingApi" => Ok(Self::StartingApi),
108            "Running" => Ok(Self::Running),
109            "Degraded" => Ok(Self::Degraded),
110            "Restricted" => Ok(Self::Restricted),
111            "ShuttingDown" => Ok(Self::ShuttingDown),
112            "Stopped" => Ok(Self::Stopped),
113            _ => Err(RuntimeError::InvalidStateTransition),
114        }
115    }
116}
117
118impl RuntimeLifecycleEvent {
119    fn as_event_name(self) -> EventName {
120        // appcore-norm: allow(clippy::unwrap_used) reason: enum mapping uses validated static event names
121        EventName::new(match self {
122            RuntimeLifecycleEvent::ConfigLoaded => "ConfigLoaded",
123            RuntimeLifecycleEvent::SecurityChecked => "SecurityChecked",
124            RuntimeLifecycleEvent::StorageOpened => "StorageOpened",
125            RuntimeLifecycleEvent::ApiStarted => "ApiStarted",
126            RuntimeLifecycleEvent::DegradedDetected => "DegradedDetected",
127            RuntimeLifecycleEvent::RestrictedDetected => "RestrictedDetected",
128            RuntimeLifecycleEvent::ShutdownRequested => "ShutdownRequested",
129            RuntimeLifecycleEvent::ShutdownCompleted => "ShutdownCompleted",
130            RuntimeLifecycleEvent::RecoveryCompleted => "RecoveryCompleted",
131        })
132        .unwrap()
133    }
134}
135
136impl RuntimeLifecycle {
137    /// Creates a lifecycle in the booting state with all valid transitions.
138    pub fn new() -> Self {
139        // Máquina de estados explícita para o ciclo de vida do runtime.
140        // Todas as transições são rígidas e validadas; qualquer transição inválida gera erro imediato
141        // e impede o avanço de estado incorreto.
142        let mut machine = StateMachine::new(RuntimeLifecycleState::Booting.as_state_name());
143        let transitions = vec![
144            (
145                RuntimeLifecycleState::Booting,
146                RuntimeLifecycleEvent::ConfigLoaded,
147                RuntimeLifecycleState::CheckingSecurity,
148            ),
149            (
150                RuntimeLifecycleState::CheckingSecurity,
151                RuntimeLifecycleEvent::SecurityChecked,
152                RuntimeLifecycleState::OpeningStorage,
153            ),
154            (
155                RuntimeLifecycleState::OpeningStorage,
156                RuntimeLifecycleEvent::StorageOpened,
157                RuntimeLifecycleState::StartingApi,
158            ),
159            (
160                RuntimeLifecycleState::StartingApi,
161                RuntimeLifecycleEvent::ApiStarted,
162                RuntimeLifecycleState::Running,
163            ),
164            (
165                RuntimeLifecycleState::Running,
166                RuntimeLifecycleEvent::DegradedDetected,
167                RuntimeLifecycleState::Degraded,
168            ),
169            (
170                RuntimeLifecycleState::Running,
171                RuntimeLifecycleEvent::RestrictedDetected,
172                RuntimeLifecycleState::Restricted,
173            ),
174            (
175                RuntimeLifecycleState::Degraded,
176                RuntimeLifecycleEvent::RecoveryCompleted,
177                RuntimeLifecycleState::Running,
178            ),
179            (
180                RuntimeLifecycleState::Restricted,
181                RuntimeLifecycleEvent::RecoveryCompleted,
182                RuntimeLifecycleState::Running,
183            ),
184            (
185                RuntimeLifecycleState::Running,
186                RuntimeLifecycleEvent::ShutdownRequested,
187                RuntimeLifecycleState::ShuttingDown,
188            ),
189            (
190                RuntimeLifecycleState::Degraded,
191                RuntimeLifecycleEvent::ShutdownRequested,
192                RuntimeLifecycleState::ShuttingDown,
193            ),
194            (
195                RuntimeLifecycleState::Restricted,
196                RuntimeLifecycleEvent::ShutdownRequested,
197                RuntimeLifecycleState::ShuttingDown,
198            ),
199            (
200                RuntimeLifecycleState::ShuttingDown,
201                RuntimeLifecycleEvent::ShutdownCompleted,
202                RuntimeLifecycleState::Stopped,
203            ),
204        ];
205
206        for (from, event, to) in transitions {
207            let _ = machine.add_transition(StateTransition {
208                from: from.as_state_name(),
209                event: event.as_event_name(),
210                to: to.as_state_name(),
211            });
212        }
213
214        Self {
215            machine: Mutex::new(machine),
216        }
217    }
218
219    /// Returns the current lifecycle state.
220    pub fn current(&self) -> RuntimeLifecycleState {
221        let guard = self.machine.lock();
222        match RuntimeLifecycleState::from_state_name(guard.current()) {
223            Ok(state) => state,
224            Err(_) => RuntimeLifecycleState::Booting,
225        }
226    }
227
228    /// Applies one lifecycle event and returns the resulting state.
229    pub fn apply(&self, event: RuntimeLifecycleEvent) -> RuntimeResult<RuntimeLifecycleState> {
230        let mut guard = self.machine.lock();
231        let next = guard.apply(&event.as_event_name())?;
232        RuntimeLifecycleState::from_state_name(next)
233    }
234
235    /// Reports whether the lifecycle is in the normal running state.
236    pub fn is_running(&self) -> bool {
237        self.current() == RuntimeLifecycleState::Running
238    }
239
240    /// Reports whether shutdown has completed.
241    pub fn is_stopped(&self) -> bool {
242        self.current() == RuntimeLifecycleState::Stopped
243    }
244
245    /// Reports whether restricted operation is active.
246    pub fn is_restricted(&self) -> bool {
247        self.current() == RuntimeLifecycleState::Restricted
248    }
249}
250
251impl Default for RuntimeLifecycle {
252    fn default() -> Self {
253        Self::new()
254    }
255}
256
257#[cfg(test)]
258#[path = "lifecycle_tests.rs"]
259mod tests;