策略

策略

关于系统,是否可以在另一个服务运行时暂停或停止正在运行的服务(确保所有数据已写入)?

我的场景如下所示:我构建了一个传感器(基于 Raspberry Pi Zero W 并运行 Kali Linux)。用于感知的守护进程sensor.service在引导过程完成后立即启动(作为 systemd 服务单元)。

[Unit]
Description=Arbitrary sensor
After=network.target

[Service]
ExecStart=/usr/local/bin/sense --daemon

[Install]
WantedBy=multi-user.target

传感器在本地连续收集和存储数据。数据被定期计算,其结果将被发送出去(通过网络)。现在,在计算时传感器应停止接收更多数据以确保所有数据均已写入,在计算开始之前。计算完成后,传感器应开始收集进一步的数据。

是的,我可以自己编写一个脚本来处理这个问题:

systemctl stop sensor.service
systemctl start compute.service  # Terminates itself
systemctl start sensor.service

但我想知道,这是不是 systemd 可以为我处理的场景?尤其是不需要自己写脚本。我想象的是一个compute.timer处理上面三行的单元。

答案1

您在问题中编写的脚本有一个小问题。它不会等到compute.service停止才开始sensor.service


策略

这里有四种策略。我认为第三个是我最喜欢的。

寻找另一种并发方式

我不确定是否sensor.service有必要停下来。听起来您这样做的原因是为了让新数据不会影响计算。在这种情况下,我会拍摄数据文件的快照。然后根据该快照进行计算。该快照在计算过程中不会更新,从而解决了并发问题。使用PrivateTmp=意味着您/tmp实际上是一个新的临时安装,当服务停止时将被删除。

# /etc/systemd/system/compute.service
[Service]
ExecStartPre=/bin/cp /var/lib/sensor/data /tmp/data_to_compute
ExecStart=/usr/bin/compute /tmp/data_to_compute
PrivateTmp=yes

在定时脚本中完成这一切

如果确实有必要停止sensor.service,那么您的脚本想法还不错。我可能会拨打compute.timer其中compute.service包含ExecStart=/usr/local/bin/compute.sh.这将包含这样的内容:

#!/bin/sh
systemctl stop sensor.service
/usr/bin/compute /var/lib/sensor/data
systemctl start sensor.service

使用系统关系

在前面的示例中,我们systemctl从 systemd 运行的脚本内部进行调用。感觉有些不对劲。 systemd中的关系Conflicts=是指当服务启动时,会自动停止冲突的服务。 systemd 没有在另一个进程完成时启动一个进程的关系,所以我们可以ExecStartPost=在这里使用它:

因此将其添加到compute.service

[Unit]
Conflicts=sensor.service

[Service]
ExecStart=/usr/bin/compute /var/lib/sensor/data
ExecStopPost=systemctl start sensor.service

sensor.service将实现您在触发时停止的目标compute.timer。我们已将所有内容移至单元文件中,而不是自定义 shell 脚本。从 systemd 内部使用的不适问题systemctl尚未解决,但至少我们已经减少了它并使其更加透明(而不是将其隐藏在脚本中)。

两个定时器

这有点不优雅,但如果你想更换线路ExecStopPost=,你可以有两个计时器。 compute.timer设置为按照您喜欢的频率进行计算(就像您已经在做的那样)。如果您想要计算 5 分钟的数据,则设置为在触发前 5 分钟sensor.timer启动。sensor.servicecompute.timer


把它们放在一起

无论采用哪种策略,您都需要compute.timercompute.service,但不需要接触sensor.service。我意识到您可能一直在问如何制作 systemd 计时器。以下是我将如何完整实施策略 3:

# /etc/systemd/system/compute.timer
[Unit]
Description=Timer to trigger computations every 15 minutes

[Timer]
OnCalendar=*:0/15

[Install]
WantedBy=timers.target

compute.timercompute.service(上图)将每 15 分钟开始(下图)。

# /etc/systemd/system/compute.service
[Unit]
Description=Runs computation (triggered by compute.timer)
Conflicts=sensor.service

[Service]
ExecStart=/usr/bin/compute /var/lib/sensor/data
ExecStopPost=systemctl start sensor.service

然后只需启用计时器(如果您不想重新启动,则启动计时器):

systemctl enable compute.timer
systemctl start compute.timer

答案2

到目前为止我发现的解决我的问题的最佳实践在另一个问题中进行了描述:https://unix.stackexchange.com/a/318744/208465

相关内容