Skip to main content

behavior_actors/atomic/fixed_supervisor/restart/
admission.rs

1//! Fixed-supervisor naming of shared restart denials and proposals.
2
3use core::num::NonZeroUsize;
4use std::time::Instant;
5
6use super::super::super::restart::{
7    RestartAdmission as SharedRestartAdmission, RestartDenial, RestartProposal, RestartRelease,
8    RestartReleaseFailure,
9};
10use super::super::RestartLimit;
11use super::super::role::MemberRole;
12use super::RestartBudget;
13
14/// Exact reason an otherwise prepared fixed-roster recovery was denied.
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum RecoveryDenialReason {
17    /// The supervisor cannot issue another non-reused recovery ticket.
18    RecoveryTicketsExhausted,
19    /// The supervisor cannot issue another non-reused restart-timer identity.
20    RestartTimersExhausted,
21    /// The active inclusive-window charge plus this request exceeds the limit.
22    RestartLimitReached {
23        /// Replacement attempts still active inside the configured window.
24        active: u32,
25        /// Positive replacement count requested by this complete recovery.
26        requested: NonZeroUsize,
27        /// Configured maximum active replacement count.
28        maximum: u32,
29    },
30    /// The interpreter-authored stop time regressed.
31    ClockRegressed {
32        /// Latest time accepted by the restart history.
33        previous: Instant,
34        /// Regressing time carried by the triggering worker stop.
35        observed: Instant,
36    },
37    /// The triggering role's checked lifetime recovery count cannot advance.
38    RecoveryCountExhausted {
39        /// Greatest admitted recovery count representable by this policy.
40        admitted: u32,
41    },
42    /// Checked release-delay calculation failed.
43    ReleaseCalculationFailed(RestartReleaseFailure),
44}
45
46pub(in super::super) enum RestartAdmission<'a> {
47    Proposed(RestartProposal<'a>),
48    Denied {
49        budget: RestartBudget,
50        reason: RecoveryDenialReason,
51    },
52}
53
54impl RecoveryDenialReason {
55    fn restart(reason: RestartDenial) -> Self {
56        match reason {
57            RestartDenial::RestartLimitReached {
58                active,
59                requested,
60                maximum,
61            } => Self::RestartLimitReached {
62                active,
63                requested,
64                maximum,
65            },
66            RestartDenial::ClockRegressed { previous, observed } => {
67                Self::ClockRegressed { previous, observed }
68            }
69            RestartDenial::RecoveryCountExhausted { admitted } => {
70                Self::RecoveryCountExhausted { admitted }
71            }
72            RestartDenial::ReleaseCalculationFailed(reason) => {
73                Self::ReleaseCalculationFailed(reason)
74            }
75        }
76    }
77}
78
79pub(in super::super) fn admit_restart<'a, Role>(
80    role: &'a mut MemberRole<Role>,
81    budget: RestartBudget,
82    limit: RestartLimit,
83    release: RestartRelease,
84    observed_at: Instant,
85    replacements: NonZeroUsize,
86) -> RestartAdmission<'a> {
87    match super::super::super::restart::admit_restart(
88        role.recovery_count(),
89        budget,
90        limit,
91        release,
92        observed_at,
93        replacements,
94    ) {
95        SharedRestartAdmission::Proposed(proposal) => RestartAdmission::Proposed(proposal),
96        SharedRestartAdmission::Denied { budget, reason } => RestartAdmission::Denied {
97            budget,
98            reason: RecoveryDenialReason::restart(reason),
99        },
100    }
101}