我在嵌入式系统中使用systemd 231,我试图创建一个服务来监视系统中的硬件组件。以下是我试图做的事情的粗略描述:
foo.service启动时,它会启动一个应用程序foo_app。foo_app监控硬件组件,连续运行。foo_app检测到硬件故障,它将退出,返回代码为1。这将触发系统重新启动。foo_app崩溃,systemd应该重新启动foo_app。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从文档(systemd.service和systemd.service)来看,如果我以触发Restart=on-abnormal (例如killall -9 foo_app)的方式杀死foo_app,系统d应该优先于OnFailure=systemd-reboot.service而不是启动systemd-reboot.service。
然而,这不是我所看到的。一旦我杀死foo_app一次,系统就会立即重新启动。
下面是一些来自文档的相关片段:
OnFailure=:当该单元进入“失败”状态时激活的一个或多个单元的空格分隔列表。只有在达到开始限制之后,使用Restart=的服务单元才进入失败状态。Restart=注意到,服务重新启动受制于使用StartLimitIntervalSec=和StartLimitBurst=配置的单元启动速率限制,有关详细信息,请参阅systemd.unit(5)。重新启动的服务只有在达到开始限制后才进入失败状态。
这些文档似乎相当清晰:
OnFailure中指定的服务只应在服务进入"failed“状态时才运行。failed和StartLimitIntervalSec之后才能进入“StartLimitBurst”状态。这不是我看到的。
为了确认这一点,我将服务文件编辑为:
[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死亡的。这里有一个测试,在这个测试中,我反复使用SIGKILL杀死D49。
[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。
不寻常的是,每当foo.service: Unit entered failed state.被杀死时,systemd都会打印foo_app,即使它即将通过Restart=on-abnormal重新启动。这似乎直接与上面引用的文档中的这些行相矛盾:
只有在达到开始限制之后,使用Restart=的服务单元才进入失败状态。重新启动的服务只有在达到开始限制后才进入失败状态。
所有这些都让我很困惑。我是否误解了这些系统的选择?这是系统缺陷吗?任何帮助都是非常感谢的。
发布于 2018-03-28 20:23:22
Edit 2019/08/12:根据therealjumbo's的注释,修复程序已经与systemd v239合并并发布,因此,如果您由于发行版(查看CentOS)而没有被固定在某个版本上,那么更新并使其愉快!
DR;DR文档问题,目前仍然是systemd项目的一个悬而未决的问题。
事实证明,自从您提出这个问题以来,这个问题在文档和实际行为之间已经在systemd中得到了报告和D4。根据我的理解(以及我对github问题的解读),您的期望和文档匹配,所以您没有疯。
当前,无论是否已达到启动限制,systemd都会在每次尝试启动后将状态设置为失败。在这个问题上,OP写了一个有趣的关于学习骑自行车的趣闻轶事,我强烈建议你好好看看。
https://unix.stackexchange.com/questions/422933
复制相似问题