sentinel_proxy/reload/signals.rs
1//! Signal handling for configuration reload and shutdown.
2//!
3//! Bridges OS signals with the async runtime for graceful handling of
4//! SIGHUP (reload) and SIGTERM/SIGINT (shutdown).
5
6use std::sync::{mpsc, Arc, Mutex};
7
8/// Signal type for cross-thread communication
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum SignalType {
11 /// Reload configuration (SIGHUP)
12 Reload,
13 /// Graceful shutdown (SIGTERM/SIGINT)
14 Shutdown,
15}
16
17/// Signal manager for handling OS signals with async integration
18///
19/// Bridges thread-based signal handlers with the async runtime using channels.
20pub struct SignalManager {
21 /// Sender for signal notifications
22 tx: mpsc::Sender<SignalType>,
23 /// Receiver for signal notifications (wrapped for async)
24 rx: Arc<Mutex<mpsc::Receiver<SignalType>>>,
25}
26
27impl SignalManager {
28 /// Create a new signal manager
29 pub fn new() -> Self {
30 let (tx, rx) = mpsc::channel();
31 Self {
32 tx,
33 rx: Arc::new(Mutex::new(rx)),
34 }
35 }
36
37 /// Get a sender for use in signal handlers
38 pub fn sender(&self) -> mpsc::Sender<SignalType> {
39 self.tx.clone()
40 }
41
42 /// Receive the next signal (blocking)
43 ///
44 /// This should be called from an async context using spawn_blocking
45 pub fn recv_blocking(&self) -> Option<SignalType> {
46 self.rx.lock().ok()?.recv().ok()
47 }
48
49 /// Try to receive a signal without blocking
50 pub fn try_recv(&self) -> Option<SignalType> {
51 self.rx.lock().ok()?.try_recv().ok()
52 }
53}
54
55impl Default for SignalManager {
56 fn default() -> Self {
57 Self::new()
58 }
59}