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

为何设置Restart=always的systemd简单服务在主进程被杀死后未重启?

为何设置Restart=always的systemd简单服务在主进程被杀死后未重启?

我来帮你拆解这个问题的核心逻辑——你遇到的情况本质是systemd对Type=simple类型服务的进程跟踪规则和预期不一致导致的。

咱们先对应你的场景来看:你用Type=simple启动bash脚本,脚本又fork出sleep子进程。当你杀死bash主进程后,sleep还留在服务的CGroup(控制组)里,这时候systemd会认为服务仍然处于活跃运行状态,自然不会触发Restart=always的重启逻辑。

具体原因拆解

systemd判断服务是否需要重启,核心看的是服务的整体状态,而非单一主进程的状态:

  • 对于Type=simple的服务,systemd启动ExecStart指定的进程后,就会认为服务启动完成。它会监控主进程,但只要服务的CGroup里还有存活的进程,哪怕主进程挂了,systemd也会标记服务为active (running)状态。
  • 你设置的RemainAfterExit=no是指「进程全部退出后服务不保持活跃」,但这里sleep子进程没退出,CGroup里还有活进程,所以这个配置没生效,服务状态没切换到停止/失败,重启条件也就没触发。

解决办法

给你几个实用方案,按需选择:

1. 将服务类型改为Type=exec

修改test.service的[Service]段:

[Service]
Type=exec  # 替换原来的Type=simple
Restart=always
RemainAfterExit=no
ExecStart=/home/core/test.sh

Type=exec的规则是:systemd只严格跟踪ExecStart启动的那个进程,只要这个进程退出,不管有没有子进程残留,都会判定服务已退出,进而触发Restart=always重启服务。

2. 在脚本里用exec替换sleep进程

修改你的test.sh:

#!/usr/bin/env bash
set -e
exec sleep 1h  # 加上exec,让sleep直接替换bash进程

这样bash启动sleep后会直接退出,sleep变成systemd跟踪的主进程。此时不管是kill sleep(bash已经不存在了),服务都会因为主进程退出而触发重启。

3. 让主进程退出时带走子进程

你也可以在脚本里添加信号陷阱,当bash进程收到终止信号时,自动杀死sleep子进程:

#!/usr/bin/env bash
set -e
sleep 1h &
PID=$!
trap "kill $PID" EXIT TERM INT
wait $PID

这样当bash被kill时,会先杀掉sleep,CGroup里没有存活进程,服务状态会切换到失败,从而触发重启。

验证效果

不管选哪个方案,修改后记得重新加载配置并重启服务:

systemctl daemon-reload
systemctl restart test.service

再杀死主进程,就能看到systemd自动重启服务了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 13:58:12