我有一系列互斥的 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