在 systemd(UbuntuLinux 18.04 bionic 上的 v237)中,我可以创建一个服务文件(用于A.service
),并指定另一个服务Requisite=B.service
。这意味着如果我尝试启动A.service
但B.service
尚未运行,则 A.service 将不会启动。它是 的弱版本,当我尝试启动 时Requires
它将启动。B.service
A.service
有相反的情况吗?我可以说“如果 B.service 正在运行,那么不启动此服务”/“如果B.service正在运行,那么A.service就无法启动”?
文档说如果我这样做Conflicts=B.service
,启动A
将停止 B,然后启动 A。但我不希望 B 停止,我只想让 A 无法启动。我想要的Conflicts
是。Requisite
Requires
我可能要将其更改ExecStart
为会失败的 shell 命令systemctl is-active B.service
或某种黑客行为。有合适的解决方案吗?
答案1
我后来发现,这种情况的最佳选择是ExecCondition=
因为它允许您进行适当的错误控制;ExecStartPre=
如果退出时非零,将始终生成错误;同时ExecCondition=
允许停止执行而不抛出错误,或者在需要时抛出错误。这对于ExecStartPost=
处理通知非常方便(您可以设置触发器来通知服务未启动,因为另一个正在运行)。
ExecCondition= 在 ExecStartPre= 中的命令之前执行的可选命令。语法与 ExecStart= 相同,但允许多个命令行并且命令按顺序一个接一个地执行。
该行为类似于 ExecStartPre= 和条件检查的混合:当 ExecCondition= 命令以退出代码 1 到 254(含)退出时,其余命令将被跳过,并且单元不会被标记为失败。但是,如果 ExecCondition= 命令以 255 或异常退出(例如超时、被信号终止等),则该单元将被视为失败(并且将跳过其余命令)。退出代码为 0 或匹配 SuccessExitStatus= 的命令将继续执行下一个命令。
关于不要在 ExecStartPre= 中运行长时间运行的进程的建议同样适用于 ExecCondition=。在出现任何非零或异常退出(如上所述)的情况下,ExecCondition= 还将运行 ExecStopPost= 中的命令,作为停止服务的一部分。
代码逻辑都是一样的:
ExecCondition=/bin/bash -xc '/usr/bin/systemctl is-active --quiet other-unit.service && { [[ %i == "main" ]] && exit 255 || exit 1; } || exit 0'
ExecCondition=
相对于 的优势ExecStartPre=
在于,在这个例子中,它将检查此服务实例是否为“主”并以失败状态代码退出,因此您可以轻松注意到它;您也可以将其用作ExecStartPost=
和 的触发器ExecStopPost=
。
一个建议是使用多个条目,而ExecCondition=
不是在单个条目中运行太多命令(尽管允许);它将增强故障排除并防止由于超时而导致的失败状态。
答案2
通常,执行此操作的方法是使用ExecStartPre
检查其他服务是否正在运行的命令。如果命令ExecStartPre
返回错误代码,则其余启动过程将中止。
ExecStartPre=/bin/bash -c '! /usr/bin/systemctl is-active --quiet other-unit.service'