Skip to main content

rust_supervisor/spec/
shutdown.rs

1//! Shutdown budget and tree policy declarations.
2//!
3//! [`ShutdownBudget`] describes cooperative stop windows for one child.
4//! [`TreeShutdownPolicy`] extends that budget with supervisor-tree execution
5//! knobs used by the four-stage shutdown pipeline.
6
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use std::time::Duration;
10
11/// Recommended extra grace before the tree shutdown global hard deadline.
12pub const DEFAULT_FORCE_KILL_MARGIN_SECS: u64 = 5;
13
14/// Cooperative stop timing budget for one child.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
16pub struct ShutdownBudget {
17    /// Graceful stop budget for cooperative shutdown.
18    pub graceful_timeout: Duration,
19    /// Wait budget after an abort request.
20    pub abort_wait: Duration,
21}
22
23impl ShutdownBudget {
24    /// Creates a shutdown budget.
25    ///
26    /// # Arguments
27    ///
28    /// - `graceful_timeout`: Cooperative shutdown budget.
29    /// - `abort_wait`: Wait budget after abort escalation.
30    ///
31    /// # Returns
32    ///
33    /// Returns a [`ShutdownBudget`] value.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// let budget = rust_supervisor::spec::shutdown::ShutdownBudget::new(
39    ///     std::time::Duration::from_secs(1),
40    ///     std::time::Duration::from_millis(100),
41    /// );
42    /// assert_eq!(budget.graceful_timeout.as_secs(), 1);
43    /// ```
44    pub fn new(graceful_timeout: Duration, abort_wait: Duration) -> Self {
45        Self {
46            graceful_timeout,
47            abort_wait,
48        }
49    }
50}
51
52impl Default for ShutdownBudget {
53    /// Returns the recommended child shutdown budget.
54    fn default() -> Self {
55        Self::new(Duration::from_secs(5), Duration::from_secs(1))
56    }
57}
58
59/// Shutdown timing policy for a supervisor tree.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
61pub struct TreeShutdownPolicy {
62    /// Default cooperative stop budget inherited by children without an override.
63    pub budget: ShutdownBudget,
64    /// Whether asynchronous stragglers may be aborted after the timeout.
65    pub abort_after_timeout: bool,
66    /// Extra grace beyond the tree budget before the global hard deadline.
67    pub force_kill_margin: Duration,
68    /// Maximum orphaned child tasks before controlled process exit.
69    ///
70    /// When set to 0, the threshold is computed automatically from worker count.
71    pub max_orphan_threshold: u32,
72}
73
74impl TreeShutdownPolicy {
75    /// Creates a tree shutdown policy.
76    ///
77    /// # Arguments
78    ///
79    /// - `budget`: Default cooperative stop budget for the tree.
80    /// - `abort_after_timeout`: Whether async stragglers may be aborted.
81    /// - `force_kill_margin`: Extra grace before the global hard deadline.
82    /// - `max_orphan_threshold`: Max orphan count before process exit.
83    ///   Pass 0 to compute automatically.
84    ///
85    /// # Returns
86    ///
87    /// Returns a [`TreeShutdownPolicy`].
88    pub fn new(
89        budget: ShutdownBudget,
90        abort_after_timeout: bool,
91        force_kill_margin: Duration,
92        max_orphan_threshold: u32,
93    ) -> Self {
94        Self {
95            budget,
96            abort_after_timeout,
97            force_kill_margin,
98            max_orphan_threshold,
99        }
100    }
101
102    /// Creates a tree policy from one budget and recommended tree defaults.
103    ///
104    /// # Arguments
105    ///
106    /// - `budget`: Default cooperative stop budget for the tree.
107    ///
108    /// # Returns
109    ///
110    /// Returns a [`TreeShutdownPolicy`] with abort enabled and automatic orphan threshold.
111    pub fn with_budget(budget: ShutdownBudget) -> Self {
112        Self::new(
113            budget,
114            true,
115            Duration::from_secs(DEFAULT_FORCE_KILL_MARGIN_SECS),
116            0,
117        )
118    }
119}
120
121impl Default for TreeShutdownPolicy {
122    /// Returns the recommended tree shutdown policy.
123    fn default() -> Self {
124        Self::with_budget(ShutdownBudget::default())
125    }
126}