我有一个运行软件的服务,该软件会生成一些配置文件(如果它们不存在),并读取它们(如果存在)。我一直面临的问题是这些文件有时会损坏,导致软件无法启动,从而导致服务失败。在这种情况下,我想删除这些文件并重新启动服务。
我尝试创建一个在失败时应该执行的服务,方法如下:
[Service]
ExecStart=/bin/run_program
OnFailure=software-fail.service
该服务在哪里:
[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=systemctl --user start software.service
但问题是,即使服务失败,该服务也不会启动。
我尝试做
systemctl --user enable software-fail.service
但每次系统启动时它都会启动,就像任何其他服务一样。
我的临时解决方案是使用
ExecStopPost=/bin/rm /file/to/delete
但这不是一个令人满意的解决方法,因为无论是否由于故障导致,它在停止服务时总会删除该文件。
失败时输出:
● software.service - Software
Loaded: loaded (/home/trippelganger/.config/systemd/user/software.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Fri 2018-05-04 09:05:26 CEST; 5s ago
Process: 1839 ExecStart=/bin/run_program (code=exited, status=1/FAILURE)
Main PID: 1839 (code=exited, status=1/FAILURE)
May 04 09:05:26 trippelganger systemd[595]: software.service: Main process exited, code=exited, status=1/FAILURE
May 04 09:05:26 trippelganger systemd[595]: software.service: Unit entered failed state.
May 04 09:05:26 trippelganger systemd[595]: software.service: Failed with result 'exit-code'.
systemctl --user status software-fail.service 的输出是:
● software-fail.service - Delete corrupt files
Loaded: loaded (/home/trippelganger/.config/systemd/user/software-fail.service; disabled; vendor preset: enabled)
Active: inactive (dead)
答案1
笔记:您可能想使用ExecStopPost=
而不是OnFailure=
在这里(请参阅我的其他答案),但这试图解决您的OnFailure=
设置不起作用的原因。
无法启动设备的问题OnFailure=
可能是因为它位于错误的部分,它需要位于该[Unit]
部分而不是[Service]
。
你可以尝试这个:
# software.service
[Unit]
Description=Software
OnFailure=software-fail.service
[Service]
ExecStart=/bin/run_program
和:
# software-fail.service
[Unit]
Description=Delete corrupt files
[Service]
ExecStart=/bin/rm /file/to/delete
ExecStop=/bin/systemctl --user start software.service
我可以通过这个设置让它工作。
但请注意,OnFailure=
这里使用并不理想,因为您无法真正说出程序失败的原因,并且ExecStop=
通过直接调用来链接它的另一个启动是相当老套的......使用并查看退出状态的/bin/systemctl start
解决方案绝对是优越的。ExecStopPost=
如果你定义OnFailure=
inside [Service]
,systemd(至少是 Fedora 27 的 234 版本)会抱怨:
software.service:6: Unknown lvalue 'OnFailure' in section 'Service'
不确定您是否在日志中看到了这一点...(也许这是在最近的 systemd 中添加的?)这应该暗示那里发生了什么。
答案2
为了在服务失败时执行一些清理,您可以使用ExecStopPost=
,无论服务成功与否都会执行。
在运行的代码中,您可以使用、或ExecStopPost=
之一来确定失败条件并采取相应的操作。请参阅$SERVICE_RESULT
$EXIT_CODE
$EXIT_STATUS
文档查看这些环境变量以检查哪一个适合您。
然后您可以使用Restart=on-failure
systemd 在发生故障时尝试重新启动您的设备。
把它们放在一起,这就是它的样子。假设run_program
每当文件损坏时都会以状态 2 退出(希望您可以将其适应上述文档中的其他故障场景),这应该可以工作:
[Service]
ExecStart=/bin/run_program
ExecStopPost=/bin/sh -c 'if [ "$$EXIT_STATUS" = 2 ]; then rm /file/to/delete; fi'
Restart=on-failure
(笔记:双美元符号$$
是将其转义到 systemd,以便 shell 看到$EXIT_STATUS
并访问该变量。使用单个美元符号也可以,但是 systemd 会进行替换,并且 shell 会看到[ "2" = 2 ]
,这可以说也可以工作......无论如何,您可以通过将所有这些逻辑放入 shell 脚本并调用来绕过大部分内容通过其完整路径ExecStopPost=
,这可能会更好,您还可以轻松地向脚本添加更多命令,例如记录从错误情况中恢复所采取的操作。)
希望这将为您提供足够的指导,以了解如何根据您的特定情况正确配置!
答案3
需要警惕的是systemd
版本。$EXIT_STATUS
2017 年 5 月发布的 systemd 版本 232 引入了优点和相关值
一些发行版(在打字时)如 RHEL 7.x 仍在使用 systemd 版本 219,它不会设置像$EXIT_STATUS
.因此你不能使用上面的优秀建议:( ...