好的,这是一个非常关键的概念。在 systemd
的 Restart=
指令中,on-failure
是最常用的配置值之一。
on-failure
的含义
简单来说,Restart=on-failure
表示:仅在服务进程“异常失败”时,systemd 才会自动重启它。
这里的“异常失败”具体指的是以下几种情况:
进程以非零退出状态码退出 (Non-zero exit code):
- 这是最常见的情况。在 Unix/Linux 惯例中,退出码为
0
表示成功,任何非零值(如1
,127
,255
等)都表示某种错误或失败。 - 举例:你的服务程序遇到了致命错误,调用
exit(1)
退出了。
- 这是最常见的情况。在 Unix/Linux 惯例中,退出码为
进程由于信号而终止 (Terminated by a signal):
- 进程被某个信号(Signal)强制杀死,但这个信号不是由 systemd 本身在正常停止或重启服务时发出的。
- 典型例子:段错误 (Segmentation fault) 会触发
SIGSEGV
信号,导致进程终止。这种情况下 systemd 会重启服务。 - 反例:当你运行
systemctl stop your-service.service
时,systemd 会发送SIGTERM
(或配置的KillSignal
)来优雅地停止服务。在这种情况下,即使进程被信号终止,也不会触发重启,因为这是预期的正常行为。
进程操作超时 (Operation timeout):
- 如果为服务配置了
TimeoutStartSec=
或TimeoutStopSec=
,并且在规定时间内启动或停止没有完成,systemd 会强制终止进程。这种因超时而导致的终止也会触发on-failure
重启。
- 如果为服务配置了
进程的守护进程初始化失败 (Watchdog failure):
- 这是一个更高级的场景。如果配置了硬件看门狗 (
WatchdogSec=
),并且服务没有按时“报平安”,systemd 会认为服务挂起并将其终止,然后触发重启。
- 这是一个更高级的场景。如果配置了硬件看门狗 (
on-failure
与其它选项的对比
为了更好地理解它,可以看看其他常用的 Restart=
选项:
选项值 | 含义 | 适用场景 |
---|---|---|
no |
永不自动重启。 | 简单的、运行一次就结束的任务,或者需要人工介入处理的故障。 |
on-success |
仅在成功退出后重启(即退出码为 0 )。 |
极其罕见。通常用于需要循环执行但每次都必须成功才继续的任务。 |
on-failure |
仅在异常失败时重启(非零退出码、意外信号等)。 | 最常用。适用于需要持续运行的后台守护进程(daemons)。 |
on-abnormal |
仅在因信号或超时等“异常”情况终止时重启。(比 on-failure 范围窄) |
较少使用,用于区分正常退出和异常退出的场景。 |
on-watchdog |
仅在看门狗超时时重启。 | 高级用途,用于配置了硬件看门狗的服务。 |
always |
无条件总是重启。无论进程如何退出(即使是正常停止),systemd都会重启它。 | Docker容器、某些必须保证“永远在线”的激进策略。使用时需谨慎,因为用 systemctl stop 可能无法停止服务(需要配合 KillMode=mixed 等)。 |
.service
文件配置示例
[Unit]
Description=My Awesome Service
[Service]
Type=simple
ExecStart=/usr/bin/my-awesome-service
# Restart策略:在失败时重启
Restart=on-failure
# 如果连续启动太快,等待10秒再尝试重启
RestartSec=10s
# “异常失败”的判断条件:在60秒内最多允许重启5次
StartLimitIntervalSec=60
StartLimitBurst=5
[Install]
WantedBy=multi-user.target
⚠️重要提示:防止重启风暴
仅仅设置 Restart=on-failure
可能导致系统在服务有固有启动缺陷时陷入不断重启的循环(“重启风暴”)。因此,强烈建议同时配置以下两个参数来控制频率:
-
设置一个时间窗口(例如StartLimitIntervalSec=<时长>
60s
,1min
)。 -
在上述时间窗口内允许的最大启动次数。StartLimitBurst=<次数>
如果在一分钟内 restarting超过了这个限制次数, systemd将不再尝试重新启动该单元,并会把该单元置入failed状态.
###总结
总而言之,
- on success: exit code ==0 && exit signal is not one of the following: SIGHUP, SIGINT, SIGTERM, SIGPIPE, and also not be an unclean exit as result of a timeout or watchdog.
- on failure: exit code !=0 || exit signal is one of the following: SIGHUP, SIGINT, SIGTERM, SIGPIPE, and also be an unclean exit as result of a timeout or watchdog.
- on abnormal: exit signal is one of the following: SIGHUP, SIGINT, SIGTERM, SIGPIPE, and also be an unclean exit as result of a timeout or watchdog.
- on abort: only when the service process exits withSIGABRT or due to an uncaught critical exception that triggers such behaviour.
所以对于你的问题来说:
- ExecStartPost脚本执行失败(以非0状态码退出),会被视为一种failure.如果主服务的Restart=设置为包含这种情况(例如设置为always),那么主服务可能会被标记为失败并被尝试restart.
- ExecStartPost脚本卡住无法退出(不返回),这会导致整个service startup过程超时(如果设置了TimeoutStartSec).这种超时属于一种unclean exit/abnormal termination.同样根据主服务的Restart策略来决定是否要restart.
所以答案是:取决于主服务的 Restart=和SuccessExitStatus等参数的配置.默认情况下(Restart=no),不会自动restart;但如果明确配置了比如 Restart=on-failure/always ,那么这两种情况都可能触发auto-restart.
内容由零声教学AI助手提供,问题来源于学员提问