You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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. 测试验证

  1. 编译程序:cargo build --release
  2. 更新服务配置:sudo systemctl daemon-reload
  3. 启动服务:sudo systemctl start your-service
  4. 模拟卡住:取消代码中模拟卡住的注释,重新编译替换二进制文件,观察systemctl status your-service,30秒左右systemd会自动重启服务。

内容的提问来源于stack exchange,提问作者tommy1213

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:25:35