You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过systemd watchdog传递新参数重启daemon程序及冻结的systemd管理应用

如何通过systemd watchdog传递新参数重启daemon程序及冻结的systemd管理应用

嘿,这个需求其实挺典型的——既要让systemd监测到应用冻结时自动重启,又要让重启后的启动参数和系统初次启动时不一样。我给你拆解成两步来实现,都是systemd生态里的常规操作:

第一步:用systemd Watchdog监测应用冻结

首先得让systemd能感知到应用“挂了”,这里用systemd原生的Watchdog机制最靠谱,比自己写监控脚本省心多了。

核心配置要点:

  • 在你的应用.service文件里,加上WatchdogSec参数,比如设成30秒(意思是如果30秒收不到应用的心跳,就判定为冻结)
  • 开启Restart=on-watchdog,明确告诉systemd只有在watchdog触发时才重启(当然你也可以结合其他重启条件,比如Restart=on-failure,看你需求)
  • 把服务类型设为Type=notify,因为systemd需要接收应用主动发送的心跳信号

应用端配合:

你的应用代码里需要定期调用systemd的sd_notify函数发送心跳,比如每隔15秒发一次WATCHDOG=1的信号。如果是C/C++程序,直接用libsystemd库的函数就行;如果是脚本语言,也可以用systemd-notify命令来发送,比如在Python里可以调用subprocess执行这个命令。

要是你的应用实在没法改代码支持心跳,也可以用个变通办法:写个小脚本定期检查应用的健康状态,然后替它发心跳,但这种方式不如原生支持稳定。

第二步:让重启时使用不同的启动参数

默认情况下,systemd重启服务时会复用原来的ExecStart命令,所以要换参数得绕个小弯——用启动脚本做中间层,根据“是否是第一次启动”来切换参数。

编写启动脚本:

比如创建/usr/local/bin/start-myapp.sh,内容如下:

#!/bin/bash
# 定义标记文件,用来判断是不是初次启动(系统重启后这个文件会消失,刚好符合需求)
FLAG_FILE="/var/run/myapp_restarted.flag"

if [ ! -f "$FLAG_FILE" ]; then
    # 系统初次启动时,用默认参数
    echo "Starting with normal arguments..."
    /usr/bin/myapp --normal-mode --port 8080
    # 启动成功后创建标记文件,下次重启就会用新参数
    touch "$FLAG_FILE"
else
    # 重启时用恢复参数
    echo "Restarting with recovery arguments..."
    /usr/bin/myapp --recovery-mode --port 8081
fi

别忘了给脚本加执行权限:chmod +x /usr/local/bin/start-myapp.sh

更新service文件:

把原来的ExecStart指向这个脚本,还要加上ExecStopPost在服务正常停止时删掉标记文件(比如系统关机时),这样下次开机又会回到初次启动的参数:

[Unit]
Description=My Frozen-Aware Application
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/start-myapp.sh
# 30秒没心跳就判定为冻结
WatchdogSec=30s
# 只有watchdog触发时才重启,也可以改成on-failure覆盖更多场景
Restart=on-watchdog
# 重启间隔设5秒,避免频繁重启
RestartSec=5s
User=myapp-user
WorkingDirectory=/var/lib/myapp
# 正常停止时删除标记文件
ExecStopPost=/bin/rm -f /var/run/myapp_restarted.flag

[Install]
WantedBy=multi-user.target

测试验证

配置完后,先重新加载systemd配置:systemctl daemon-reload,然后启动服务:systemctl start myapp.service

可以手动模拟冻结:用kill -STOP <pid>来暂停应用进程,这样它就没法发心跳了,等30秒左右systemd就会重启它,这时候你看日志journalctl -u myapp.service就能看到是用恢复参数启动的。

备注:内容来源于stack exchange,提问作者Dimitri Ratz

火山引擎 最新活动