我有一个在云虚拟机上运行的定期任务。该机器类型非常昂贵,因此我有一个 systemd 单元服务,该服务在启动时启动,运行脚本,然后关闭机器以节省资金。这按设计工作。
我在维护机器时遇到了麻烦,因为如果我登录并发出service [] stop
命令,系统当然会立即关闭(正如它应该的那样)。
我认为我应该能够使用OnFailure
它,但我也希望系统在脚本因某种原因失败时关闭(而不是在崩溃时让虚拟机旋转)。或者一些用途ExecStop
?
会有三种情况:
- 进程正确执行并终止(例如退出代码0),系统电源关闭
- 进程崩溃(例如退出代码!= 0),系统断电
- 服务被用户终止/暂停?系统保持开启状态
简单的解决方案是在启动、登录、禁用、重新启动(因为服务已经启动)、执行维护任务然后重新启用之前给服务一分钟的宽限期。但这似乎有点笨拙。服务定义如下,供参考。
[Unit]
Description="Run job"
After=network.target
StartLimitInterval=200
StartLimitBurst=30
OnFailure=systemd-poweroff.service
[Service]
Type=simple
Restart=on-failure
RestartSec=30
ExecStartPre=/bin/sleep 60
ExecStart=/my/script.sh
ExecStopPost=sudo systemctl poweroff -i
User=foo
[Install]
WantedBy=multi-user.target
请注意,由于环境设置而不是任何安全意识,脚本以普通用户身份运行,因此这里使用 sudo (该帐户专门被授予用于关闭电源的无密码 sudo 权限)。
答案1
poweroff
不要在操作中运行,而是ExecStopPost
将其移动到单独的服务中。也就是说,让您的“运行作业”服务看起来像这样:
[Unit]
Description="Run job"
After=network.target
Requires=my-poweroff.service
Before=my-poweroff.service
[Service]
Type=oneshot
Restart=on-failure
RestartSec=30
ExecStart=/my/script.sh
User=foo
[Install]
WantedBy=multi-user.target
请注意,我们使用的是Type=oneshot
而不是Type=simple
,因为这样在脚本完成之前服务不会“启动”。这很重要,因为我们通过Requires=
/依赖项触发断电Before=
;使用Type=simple
,该作业和关机作业将开始同时。使用Type=oneshot
意味着关闭作业在该服务退出之前不会运行。
然后在 中my-poweroff.service
,你有:
[Unit]
ConditionPathExists=!/run/nopoweroff
[Service]
Type=simple
ExecStart=/usr/bin/systemctl poweroff -i
现在,如果您想在“运行作业”服务完成之前poweroff
阻止。touch /run/nopoweroff