如何在SystemD中指定时间后启动服务?

如何在SystemD中指定时间后启动服务?

我正在尝试将 SysV 初始化脚本转换为 systemd。 SysV 配置以这种方式生成不同的进程:

su -l $USER_A -c "$CMD_A &"
usleep 600000
su -l $USER_B -c "$CMD_B &"
usleep 100000
su -l $USER_C -c "$CMD_C &"
usleep 300000

因为所有生成进程都使用不同的用户,所以我一直为每个进程创建一个 systemd 服务单元。在此服务单元中,我指定了依赖项(使用 Requires+After)。例如,其中一个服务单位:

[Unit]
Description=CMD_B
Requires=CMD_A
After=CMD_A

[Service]
User=USER_B
Type=simple
ExecStart=/FULLPATH/CMD_B

[Install]
WantedBy=multi-user.target

问题是,不同的进程通过 POSIX 队列进行通信,并且这些队列不会立即创建,因此每次启动之间需要一段时间,因为它们不够强大,无法等待 POSIX 队列创建,它们只是失败了: -(

我无法更改这些流程,因此我只能在每个服务启动之间添加经过的时间。

我怎样才能“干净地”告诉systemd它应该考虑每次服务激活之间的特定时间段?

注意:虽然 systemd 尊重“之后”依赖性,但因为我认为它认为这些命令立即处于活动状态,所以它们几乎同时生成(在几毫秒内)。如果我尝试添加一个,ExecStartPost=/usr/bin/usleep 600000它们似乎也会在几毫秒内生成,因为服务的类型很简单,我想这ExecStartPost永远不会被触发。所以我尝试过ExecStartPre=/usr/bin/usleep 600000(对于CMD_B,我将CMD_C更改为100000),但现在似乎不再遵守顺序,先启动CMD_A,然后在100毫秒后启动CMD_C,最后在600毫秒后启动CMD_B。所以 CMD_C 失败,因为它先于 CMD_B 启动。我现在已经使用了这个ExecStartPre=技巧,但我为 CMD_B 选择了 600 毫秒,为 CMD_C 选择了 700 毫秒,等等。它有效,但我发现这非常糟糕。

答案1

我想提出一种不使用超时的方法,而是依赖于systemd 等待文件的机制在启动程序之前存在。

如您所知,Linux 可以将 posix 消息队列公开为文件。在我的 Fedora 系统上,它默认在 中执行此操作,但如果没有该目录,/dev/mqueue/您可以创建该目录。mount -t mqueue none /dev/mqueue

然后您可以使用(参见man systemd.path)一个像这样的简单单元myqueueb.path

[Path]
PathExists=/dev/mqueue/queueb
[Install]
WantedBy=multi-user.target

和另一个myqueueb.service 同名(或Unit=在上面设置)与

[Unit]
Description=CMD_B
[Service]
User=USER_B
Type=simple
ExecStart=/FULLPATH/CMD_B

做你想做的事。做不启用第二个单元,但是做systemctl enable myqueueb.pathsystemctl start myqueueb.path。这会在文件上设置 inotifywait /dev/mqueue/queueb

当您的第一个程序创建消息队列时queueb,该文件将出现,systemd 将自动启动myqueueb.service并运行您的程序CMD_B。显然,您还需要更改这些名称以匹配您的队列名称和 CMD_C 的关系。

相关内容