是否可以让 systemd 单元等到其所有 Conflicts= 停止后再尝试启动?

是否可以让 systemd 单元等到其所有 Conflicts= 停止后再尝试启动?

我有一系列互斥的 systemd 服务,这些服务由用户根据需要启动和停止。每项服务都需要独占使用某些硬件,因此许多服务相互冲突。 (但并非所有服务都与所有其他服务冲突)

为了管理这个问题,我使用了 Conflicts=,它几乎可以完美地工作,但是启动服务的 ExecStart 似乎在运行,而冲突服务的 ExecStop 脚本仍在运行,这会导致启动服务失败,因为硬件资源不足尚不可用。

如果我让启动脚本休眠一段安全的时间(例如 30 秒),它们就会完美运行,但我更希望它们在冲突的服务停止后立即启动。

After= 似乎不起作用,因为服务可以以任意顺序重复停止和启动,并且 After= 会导致循环依赖。

有没有办法在 systemd 中执行此操作,而无需检查 ExecStart 脚本内是否运行冲突?

答案1

手册页systemd.unit(5)这个要说的是Conflicts=:

请注意,此设置并不意味着排序依赖关系,类似于上面描述的Wants=Requires=依赖关系。这意味着为了确保冲突单元在另一个单元启动之前停止,必须声明After=or依赖关系。Before=使用两个排序依赖项中的哪一个并不重要,因为停止作业始终在启动作业之前排序,请参阅下面Before=/中的讨论After=

换句话说,只需声明一个排序依赖即可。

答案2

我的猜测是您的ExecStop=命令正在发出异步操作,例如向进程发送终止信号,然后在进程完成关闭之前立即退出。

确保您的ExecStop=命令是同步操作,在服务完全关闭之前不会退出。

答案3

如果您的进程是Type=exec,您可以在请求终止后使用以下命令等待其终止:https://github.com/systemd/systemd/issues/13284#issuecomment-784556633

[Service]
# Type must be set correctly for $MAINPID detection to work
Type=exec
ExecStart=/path/to/myservice/start-command
ExecStop=/path/to/myservice/stop-command
ExecStop=/usr/bin/sh -c 'while kill -0 $MAINPID 2>/dev/null; do sleep 1; done'
TimeoutStopSec=15

相关内容