Skip to main content

nodedb_types/config/tuning/
shutdown.rs

1//! Shutdown tuning — deadlines applied to the graceful shutdown
2//! path by `main.rs` and `control::shutdown::LoopRegistry`.
3
4use serde::{Deserialize, Serialize};
5
6fn default_shutdown_deadline_ms() -> u64 {
7    // 900ms: the remaining 100ms of a 1s operator budget is
8    // reserved for transport close + final WAL fsync. Chosen
9    // so `shutdown_all` has a chance to abort async laggards
10    // before the OS hard-kills the process on a second SIGTERM.
11    900
12}
13
14/// Tuning knobs for the graceful shutdown path.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct ShutdownTuning {
17    /// Deadline in milliseconds for `LoopRegistry::shutdown_all`.
18    /// Every registered background loop must exit within this
19    /// window after the shutdown signal is flipped; laggards
20    /// are aborted (async) or logged (blocking).
21    #[serde(default = "default_shutdown_deadline_ms")]
22    pub deadline_ms: u64,
23}
24
25impl Default for ShutdownTuning {
26    fn default() -> Self {
27        Self {
28            deadline_ms: default_shutdown_deadline_ms(),
29        }
30    }
31}
32
33impl ShutdownTuning {
34    /// Convert the deadline to a `std::time::Duration`.
35    pub fn deadline(&self) -> std::time::Duration {
36        std::time::Duration::from_millis(self.deadline_ms)
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn default_deadline_is_900ms() {
46        let t = ShutdownTuning::default();
47        assert_eq!(t.deadline_ms, 900);
48        assert_eq!(t.deadline(), std::time::Duration::from_millis(900));
49    }
50
51    #[test]
52    fn override_deadline() {
53        let toml_str = r#"deadline_ms = 1500"#;
54        let t: ShutdownTuning = toml::from_str(toml_str).unwrap();
55        assert_eq!(t.deadline_ms, 1500);
56    }
57}