如何让Rust程序与systemd WatchDog通信并实现进程重启?
Rust程序向systemd发送看门狗通知实现方案
核心问题说明
你之前配置的WatchdogSec=30和Restart=on-watchdog未触发重启,是因为systemd默认看门狗仅监控进程是否崩溃,程序卡住但进程存活的情况不会自动触发。必须让程序定期主动向systemd发送心跳通知,当心跳中断时,systemd才会执行重启。
实现步骤
1. 添加依赖
在Cargo.toml中引入libsystemd crate,它封装了systemd的通知API:
[dependencies] libsystemd = "0.6"
2. 代码实现
以下是完整代码示例,包含后台线程监控主程序活跃状态、定期发送心跳的逻辑,完全匹配你“无输出则重启”的需求:
use libsystemd::notify::{notify, NotifyState}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; use std::time::Duration; fn main() { // 原子变量标记主程序是否活跃(产生输出/正常执行) let is_active = Arc::new(AtomicBool::new(true)); let is_active_clone = Arc::clone(&is_active); // 启动后台看门狗线程 let _watchdog_guard = thread::spawn(move || { let mut last_check_inactive = false; loop { // 读取主程序活跃状态 let current_active = is_active_clone.load(Ordering::Relaxed); if current_active { // 向systemd发送心跳通知 if let Err(e) = notify(false, &[NotifyState::Watchdog]) { eprintln!("Failed to send watchdog heartbeat: {}", e); break; } // 重置标记,等待主程序下次更新 is_active_clone.store(false, Ordering::Relaxed); last_check_inactive = false; } else { if last_check_inactive { // 连续两次检查都未收到主程序的活跃信号,停止发送心跳 eprintln!("Main program is stuck, stopping watchdog heartbeats"); break; } last_check_inactive = true; } // 每隔25秒检查一次,比WatchdogSec=30短,留足容错时间 thread::sleep(Duration::from_secs(25)); } }); // -------------------------- // 替换为你的主程序业务逻辑 // -------------------------- loop { // 模拟程序产生输出的场景,每次输出后标记为活跃 println!("Processing tasks..."); is_active.store(true, Ordering::Relaxed); // 模拟业务处理耗时 thread::sleep(Duration::from_secs(10)); // 测试用:取消注释以下代码,模拟主程序卡住无输出的情况 // thread::sleep(Duration::from_secs(40)); } }
3. 关键细节解释
- 自动识别服务上下文:
notify(false, ...)中的false表示自动通过systemd设置的NOTIFY_SOCKET环境变量发送通知,无需手动指定PID或套接字路径,只要程序由systemd启动即可正常工作。 - 活跃状态监控:主程序每次产生输出或完成关键任务时,更新
is_active原子变量;后台线程定期检查该变量,只有主程序正常运行时才发送心跳。 - 心跳频率:设置为25秒一次,比
WatchdogSec=30短,避免因网络延迟或调度延迟导致误触发重启。
4. 确认systemd服务配置
确保你的服务文件(如/etc/systemd/system/your-service.service)包含以下配置:
[Unit] Description=Your Rust Application After=network.target [Service] Type=simple ExecStart=/path/to/your/compiled/rust/binary WatchdogSec=30 Restart=on-watchdog RestartSec=5 User=your-username Group=your-groupname [Install] WantedBy=multi-user.target
5. 测试验证
- 编译程序:
cargo build --release - 更新服务配置:
sudo systemctl daemon-reload - 启动服务:
sudo systemctl start your-service - 模拟卡住:取消代码中模拟卡住的注释,重新编译替换二进制文件,观察
systemctl status your-service,30秒左右systemd会自动重启服务。
内容的提问来源于stack exchange,提问作者tommy1213
相关产品推荐
相关产品推荐

