将 systemd 行为与 OnFailure= 和 Restart= 混淆

将 systemd 行为与 OnFailure= 和 Restart= 混淆

我在嵌入式系统中使用 systemd 231,并且尝试创建一个监视系统中硬件组件的服务。这是我想要做的事情的粗略描述:

  1. 当服务 ,foo.service启动时,它会启动一个应用程序 , foo_app
  2. foo_app监视持续运行的硬件组件。
  3. 如果foo_app检测到硬件故障,它将退出并返回代码 1。这应该会触发系统重新启动。
  4. 如果foo_app崩溃,systemd 应重新启动foo_app
  5. 如果foo_app 反复崩溃时,systemd 应该重新启动系统。

这是我将其实现为服务的尝试:

[Unit]
Description=Foo Hardware Monitor

# If the application fails 3 times in 30 seconds, something has gone wrong,
# and the state of the hardware can't be guaranteed. Reboot the system here.
StartLimitBurst=3
StartLimitIntervalSec=30
StartLimitAction=reboot

# StartLimitAction=reboot will reboot the box if the app fails repeatedly,
# but if the app exits voluntarily, the reboot should trigger immediately
OnFailure=systemd-reboot.service

[Service]
ExecStart=/usr/bin/foo_app

# If the app fails from an abnormal condition (e.g. crash), try to
# restart it (within the limits of StartLimit*).
Restart=on-abnormal

从文档(系统服务系统服务),我希望如果我foo_app以触发的方式杀死Restart=on-abnormal(例如killall -9 foo_app), systemd 应该优先考虑Restart=on-abnormaloverOnFailure=systemd-reboot.service而不是 start systemd-reboot.service

然而,这不是我所看到的。只要我杀foo_app一次,系统就会立即重新启动。

以下是文档中的一些相关片段:

OnFailure=

当该单元进入“失败”状态时激活的一个或多个单元的以空格分隔的列表。仅在达到启动限制后,使用 Restart= 的服务单元才会进入故障状态。

Restart=

[剪]请注意,服务重新启动受 StartLimitIntervalSec= 和 StartLimitBurst= 配置的单元启动速率限制的约束,有关详细信息,请参阅 systemd.unit(5)。仅在达到启动限制后,重新启动的服务才会进入失败状态。

文档看起来很清楚:

  • 中指定的服务OnFailure仅应在服务进入“ failed”状态时运行
  • 服务只有在满足后才应进入“ failed”状态。StartLimitIntervalSecStartLimitBurst

这不是我所看到的。

为了确认这一点,我将服务文件编辑为以下内容:

[Unit]
Description=Foo Hardware Monitor  
  
StartLimitBurst=3
StartLimitIntervalSec=30
StartLimitAction=none

[Service]
ExecStart=/usr/bin/foo_app
Restart=on-abnormal

通过删除OnFailure和设置StartLimitAction=none,我能够看到 systemd 如何响应foo_app死亡。这是我反复foo_app使用 进行杀死的测试SIGKILL

[root@device ~]
# systemctl start foo.service
[root@device ~]
# journalctl -f -o cat -u foo.service &
[1] 2107
Started Foo Hardware Monitor.
[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
Started foo.

[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
Started foo.

[root@device ~]
# killall -9 foo_app
foo.service: Main process exited, code=killed, status=9/KILL
foo.service: Unit entered failed state.
foo.service: Failed with result 'signal'
foo.service: Service hold-off time over, scheduling restart.
Stopped foo.
foo.service: Start request repeated too quickly
Failed to start foo.
foo.service: Unit entered failed state.
foo.service: Failed with result 'start-limit-hit'

这是有道理的,或者说大部分是有道理的。当foo_app被杀死时,systemd 会重新启动它,直到StartLimitBurst被击中,然后放弃。这就是我想要的,除了StartLimitAction=reboot.

不寻常的是,systemdfoo.service: Unit entered failed state.每当foo_app被杀死时都会打印,即使它即将通过 重新启动Restart=on-abnormal。这似乎与上面引用的文档中的这些行直接矛盾:

仅在达到启动限制后,使用 Restart= 的服务单元才会进入故障状态。

仅在达到启动限制后,重新启动的服务才会进入失败状态。

所有这一切都让我很困惑。我是否误解了这些 systemd 选项?这是系统错误吗?任何帮助表示赞赏。

答案1

2019/08/12 编辑:根据therealjumbo的评论,此问题的修复已与systemdv239 合并并发布,因此,如果您由于发行版而未固定到某个版本(看着你的 CentOS)更新并快乐起来!

TL;DR - 已知文档问题,目前仍然是该systemd项目的一个悬而未决的问题

事实证明,自从你问这个问题以来,这件事已经被报道了,被认定为差异介于systemd文档和实际行为之间。根据我的理解(以及我对 github 问题的阅读),你的期望和文档相符,所以你并不疯狂。

目前,systemd无论是否已达到启动限制,每次尝试启动后都会将状态设置为失败。在本期中,OP 写了一个关于学习骑自行车的有趣轶事,我强烈建议您看一下。

相关内容