Skip to main content

sqry_daemon/lifecycle/
mod.rs

1//! Task 9 lifecycle primitives.
2//!
3//! This module is the landing zone for all sqryd binary lifecycle concerns:
4//!
5//! - [`notify`] — thin `sd_notify` wrapper with platform-appropriate fallbacks.
6//!   On Linux the real `sd_notify` crate is called; on macOS and Windows the
7//!   functions are no-ops so that callers in the shared startup path never need
8//!   `#[cfg(target_os = "linux")]` guards at the call site.
9//! - [`log_rotate`] — `RollingSizeAppender` + `install_tracing` (Task 9 U5).
10//!   Rotates the active log file when it exceeds `log_max_size_mb`, keeping at
11//!   most `log_keep_rotations` copies.  When `NOTIFY_SOCKET` is present
12//!   (systemd supervision) the rolling appender is skipped and output goes to
13//!   stderr instead (§G.1 m4 fix).
14//!
15//! Modules added by later Task 9 units (U3–U10) will be declared here as they
16//! are implemented.  This avoids merge-conflict churn: each unit adds one
17//! `pub mod` line.
18//!
19//! # Design reference
20//!
21//! `docs/reviews/sqryd-daemon/2026-04-19/task-9-design_iter3_request.md` §C.3.1
22//! (step 15 — authoritative ready-signal matrix) + §F.1 (systemd user unit
23//! `Type=notify`) + §G (log rotation).
24
25pub mod detach;
26pub mod log_rotate;
27pub mod notify;
28pub mod pidfile;
29pub mod signals;
30pub mod units;
31
32#[cfg(test)]
33pub(crate) mod test_support {
34    use std::ffi::OsString;
35    use std::sync::{Mutex, MutexGuard};
36
37    static NOTIFY_SOCKET_LOCK: Mutex<()> = Mutex::new(());
38
39    pub(crate) struct NotifySocketGuard {
40        previous: Option<OsString>,
41        _lock: MutexGuard<'static, ()>,
42    }
43
44    impl NotifySocketGuard {
45        pub(crate) fn unset() -> Self {
46            let _lock = NOTIFY_SOCKET_LOCK.lock().unwrap_or_else(|e| e.into_inner());
47            let previous = std::env::var_os("NOTIFY_SOCKET");
48            unsafe {
49                std::env::remove_var("NOTIFY_SOCKET");
50            }
51            Self { previous, _lock }
52        }
53
54        pub(crate) fn set(value: &str) -> Self {
55            let _lock = NOTIFY_SOCKET_LOCK.lock().unwrap_or_else(|e| e.into_inner());
56            let previous = std::env::var_os("NOTIFY_SOCKET");
57            unsafe {
58                std::env::set_var("NOTIFY_SOCKET", value);
59            }
60            Self { previous, _lock }
61        }
62    }
63
64    impl Drop for NotifySocketGuard {
65        fn drop(&mut self) {
66            match &self.previous {
67                Some(value) => unsafe { std::env::set_var("NOTIFY_SOCKET", value) },
68                None => unsafe { std::env::remove_var("NOTIFY_SOCKET") },
69            }
70        }
71    }
72}