Skip to main content

ic_timers/snapshot/
mod.rs

1//! Provider-neutral identity and coherent canonical snapshot values.
2//!
3//! Public snapshots are inert observations with private top-level fields. The
4//! registry is their only constructor and mutation authority.
5
6mod identity;
7mod metrics;
8mod model;
9
10pub use identity::{
11    MAX_TIMER_LABEL_BYTES, TimerIdentity, TimerIdentityError, TimerIdentityField, TimerLabel,
12    TimerLabelError,
13};
14pub use metrics::{
15    MeasurementSummary, TimerCounters, TimerObservabilitySnapshot, TimerPerformance,
16};
17pub use model::{
18    DeclarationLifetime, InactiveReason, OrdinaryRuntimeStateSnapshot, TimerCompletion,
19    TimerCompletionOutcome, TimerControlFailure, TimerDirectiveSnapshot, TimerEpoch,
20    TimerLastOutcome, TimerOutcomeSnapshot, TimerPolicy, TimerProcessCondition,
21    TimerRegistrationStatus, TimerRunResult, TimerRuntimeStateSnapshot, TimerSchedulingMode,
22    WatchdogAttemptSnapshot, WatchdogAttemptStatus, WatchdogDecision, WatchdogRunResult,
23    WatchdogRuntimeStateSnapshot,
24};
25
26/// Canonical provider-neutral operator snapshot for one logical timer.
27#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct TimerSnapshot {
29    identity: TimerIdentity,
30    policy: TimerPolicy,
31    lifetime: DeclarationLifetime,
32    state: TimerRuntimeStateSnapshot,
33    scheduling_mode: TimerSchedulingMode,
34    latest_directive: Option<TimerDirectiveSnapshot>,
35    latest_requested_delay_ns: Option<u64>,
36    latest_armed_delay_ns: Option<u64>,
37    observability: TimerObservabilitySnapshot,
38}
39
40impl TimerSnapshot {
41    #[allow(clippy::too_many_arguments)]
42    pub(crate) const fn new(
43        identity: TimerIdentity,
44        policy: TimerPolicy,
45        lifetime: DeclarationLifetime,
46        state: TimerRuntimeStateSnapshot,
47        scheduling_mode: TimerSchedulingMode,
48        latest_directive: Option<TimerDirectiveSnapshot>,
49        latest_requested_delay_ns: Option<u64>,
50        latest_armed_delay_ns: Option<u64>,
51        observability: &TimerObservabilitySnapshot,
52    ) -> Self {
53        Self {
54            identity,
55            policy,
56            lifetime,
57            state,
58            scheduling_mode,
59            latest_directive,
60            latest_requested_delay_ns,
61            latest_armed_delay_ns,
62            observability: *observability,
63        }
64    }
65
66    /// Return the stable structured identity.
67    #[must_use]
68    pub const fn identity(&self) -> &TimerIdentity {
69        &self.identity
70    }
71
72    /// Return the configured scheduling policy.
73    #[must_use]
74    pub const fn policy(&self) -> TimerPolicy {
75        self.policy
76    }
77
78    /// Return whether the declaration remains after terminal stop.
79    #[must_use]
80    pub const fn lifetime(&self) -> DeclarationLifetime {
81        self.lifetime
82    }
83
84    /// Return the closed policy-specific runtime state.
85    #[must_use]
86    pub const fn state(&self) -> TimerRuntimeStateSnapshot {
87        self.state
88    }
89
90    /// Return the reason for the current authoritative schedule.
91    #[must_use]
92    pub const fn scheduling_mode(&self) -> TimerSchedulingMode {
93        self.scheduling_mode
94    }
95
96    /// Return the latest completed ordinary directive.
97    #[must_use]
98    pub const fn latest_directive(&self) -> Option<TimerDirectiveSnapshot> {
99        self.latest_directive
100    }
101
102    /// Return the latest requested relative delay.
103    #[must_use]
104    pub const fn latest_requested_delay_ns(&self) -> Option<u64> {
105        self.latest_requested_delay_ns
106    }
107
108    /// Return the latest relative delay represented by an arm effect.
109    #[must_use]
110    pub const fn latest_armed_delay_ns(&self) -> Option<u64> {
111        self.latest_armed_delay_ns
112    }
113
114    /// Return the next authoritative absolute deadline.
115    #[must_use]
116    pub const fn next_deadline_ns(&self) -> Option<u64> {
117        self.state.next_deadline_ns()
118    }
119
120    /// Return a portable registration projection.
121    #[must_use]
122    pub fn registration_status(&self) -> TimerRegistrationStatus {
123        self.state.into()
124    }
125
126    /// Return an operator-facing condition derived from coherent state.
127    #[must_use]
128    pub const fn process_condition(&self) -> TimerProcessCondition {
129        match self.state {
130            TimerRuntimeStateSnapshot::Inactive {
131                reason: InactiveReason::Cancelled,
132            } => TimerProcessCondition::Disabled,
133            TimerRuntimeStateSnapshot::Inactive {
134                reason: InactiveReason::InvariantFailure | InactiveReason::ControlFailure(_),
135            } => TimerProcessCondition::Failed,
136            TimerRuntimeStateSnapshot::Inactive {
137                reason: InactiveReason::Stopped,
138            } if matches!(
139                self.observability.outcomes().last_outcome(),
140                Some(TimerLastOutcome::Completed(
141                    TimerCompletionOutcome::RetryableFailure
142                ))
143            ) =>
144            {
145                TimerProcessCondition::Failed
146            }
147            TimerRuntimeStateSnapshot::Inactive { .. } => TimerProcessCondition::Idle,
148            TimerRuntimeStateSnapshot::Ordinary(_) | TimerRuntimeStateSnapshot::Watchdog(_)
149                if matches!(self.scheduling_mode, TimerSchedulingMode::Retry) =>
150            {
151                TimerProcessCondition::Retrying
152            }
153            TimerRuntimeStateSnapshot::Ordinary(_) | TimerRuntimeStateSnapshot::Watchdog(_) => {
154                TimerProcessCondition::Active
155            }
156        }
157    }
158
159    /// Return the latest authoritative callback generation.
160    #[must_use]
161    pub const fn generation(&self) -> Option<u64> {
162        match self.state {
163            TimerRuntimeStateSnapshot::Inactive { .. } => None,
164            TimerRuntimeStateSnapshot::Ordinary(
165                OrdinaryRuntimeStateSnapshot::Scheduled { generation, .. }
166                | OrdinaryRuntimeStateSnapshot::Running { generation },
167            ) => Some(generation),
168            TimerRuntimeStateSnapshot::Watchdog(WatchdogRuntimeStateSnapshot::Scheduled {
169                scheduler_generation,
170                ..
171            }) => Some(scheduler_generation),
172            TimerRuntimeStateSnapshot::Watchdog(WatchdogRuntimeStateSnapshot::AwaitingWork {
173                successor_generation,
174                ..
175            }) => Some(successor_generation),
176        }
177    }
178
179    /// Return epoch-scoped outcomes, counters, and measurements.
180    #[must_use]
181    pub const fn observability(&self) -> TimerObservabilitySnapshot {
182        self.observability
183    }
184
185    /// Return recovery-sensitive expected-failure state directly.
186    #[must_use]
187    pub const fn consecutive_expected_failures(&self) -> u64 {
188        self.observability.consecutive_expected_failures()
189    }
190}
191
192#[cfg(test)]
193mod tests;