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}