每天使用 OnCalendar 启动和停止一段时间的 systemd 服务

每天使用 OnCalendar 启动和停止一段时间的 systemd 服务

我有两个服务(一个视频播放器和一个图像识别守护程序),我希望它们每天早上 9 点开始运行,晚上 23 点结束运行(以及在启动时运行,尽管系统将持续运行)。对于每个服务,我创建了一个-startup.service-shutdown.service。服务组合在 和 中daemon-on.target,然后分别由和daemon-off.target触发。daemon-on.timerdaemon-off.timer

经过几次尝试和测试,我发现计时器最初会按预期触发目标,但进入的状态下下次设置为 n/a。

为了让两个应用程序使用计时器运行,这需要做大量的工作。我确信它忽略了一些显而易见的东西,如果能提供任何提示,我将不胜感激!

mpv-startup.service启动视频播放器服务:

[Unit]
Description=MPV Video Player Startup
After=xorg.target
Requires=xorg.target

[Service]
Environment=DISPLAY=:0
ExecStart=/usr/bin/python3 /opt/videoplayer/app.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=10

[Install]
Also=daemon-on.timer

recog-startup.service启动图像识别服务:

[Unit]
Description=Recog Startup Service

[Service]
Type=simple
WorkingDirectory=/opt/recog
ExecStart=/opt/recog/recog run
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=30

[Install]
Also=daemon-on.timer

mpv-shutdown.service 以一次性命令停止视频播放器服务

[Unit]
Description=MPV Video Player Shutdown

[Service]
Type=oneshot
ExecStart=/bin/systemctl --user stop mpv-startup.service

[Install]
Also=daemon-off.timer

recog-shutdown.service 以一次性命令停止图像识别服务:

[Unit]
Description=Recog Shutdown Service

[Service]
Type=oneshot
ExecStart=/bin/systemctl --user stop recog-startup.service

[Install]
Also=daemon-off.timer

daemon-on.target 结合了上述两个启动服务,并且也与 default.target 一起在启动时启用:

[Unit]
Description=Daemon Startup Target
Wants=recog-startup.service mpv-startup.service
After=recog-startup.service mpv-startup.service

[Service]
Type=oneshot

[Install]
WantedBy=default.target
Also=daemon-on.timer

daemon-off.target 结合了上述两个关闭服务:

[Unit]
Description=Daemon Shutdown Target
Wants=recog-shutdown.service mpv-shutdown.service
After=recog-shutdown.service mpv-shutdown.service

[Service]
Type=oneshot

[Install]
Also=daemon-off.timer

daemon-on.timer 设置为在上午 9 点触发 daemon-on.target:

[Unit]
Description=Daemon Startup Schedule

[Timer]
OnCalendar=9:00
Unit=recog-on.target
Persistent=true

[Install]
WantedBy=timers.target

daemon-off.timer 设置为在晚上 23 点触发 daemon-off.target:

[Unit]
Description=Daemon Shutdown Schedule

[Timer]
OnCalendar=23:00
Unit=daemon-off.target
Persistent=true

[Install]
WantedBy=timers.target

将所有这些放在下面后,~/.config/systemd/user/我以以下方式启用它们:

systemctl --user enable --now daemon-on.target
systemctl --user enable --now daemon-on.timer
systemctl --user enable --now daemon-off.timer

这将在每次启动时自动启动守护进程,在这里我希望计时器根据选项启动/停止守护进程OnCalendar=。此时systemctl --user list-timers显示我的两个计时器将在正确的时间触发(请注意,我将计时器的间隔设置为仅 3 分钟,以节省等待时间):

NEXT                         LEFT         LAST                         PASSED    UNIT            ACTIVATES
Wed 2019-06-26 12:12:00 JST  1min 4s left Wed 2019-06-26 11:35:02 JST  35min ago daemon-off.timer daemon-off.target
Wed 2019-06-26 12:15:00 JST  4min 4s left Wed 2019-06-26 11:40:48 JST  30min ago daemon-on.timer  daemon-on.target

然后关闭定时器被触发,守护进程停止,几分钟后开启定时器被触发,守护进程按预期启动。然而,再次查看定时器时,我发现它们被重置,并且 NEXT/LEFT 字段设置为 n/a,并且永远不会再次触发守护进程。这里的问题是什么?

NEXT LEFT LAST                         PASSED       UNIT            ACTIVATES
n/a  n/a  Wed 2019-06-26 12:12:06 JST  4min 18s ago daemon-off.timer daemon-off.target
n/a  n/a  Wed 2019-06-26 12:15:33 JST  50s ago      daemon-on.timer  daemon-on.target

答案1

经过进一步搜索和阅读 systemd 手册页后,我设法简化了一些事情并获得了我服务所需的行为。

首先,我在文件中放入 [Service] 部分时犯了错误.target,这没有意义。其次,我发现了一个PartOf=语句,它允许我制作一个以视频播放器和识别服务为组件的顶级应用程序。最后,通过使用Conflicts=选项,我可以使用两个相互冲突的目标来启动/停止我的应用程序。.timer附加到这些目标的 s 将在彼此之间切换,禁用或启用我的应用程序链和各自冲突的.targets。结果仍然包含在 7 个文件中,这比我想要维护的要多,但它可以按要求工作。

app.service 是顶级应用程序,尽管它是一个虚拟的,但它可以运行其他东西:

[Unit]
Description=App Service

[Service]
Type=oneshot
ExecStart=/bin/true
RemainAfterExit=yes

[Install]
WantedBy=default.target
Also=app-on.timer app-off.timer

app-mpv.service 是应用程序的视频播放器组件,因此也依赖于 xorg:

[Unit]
Description=App Video Player Service
PartOf=app.service
After=app.service
Requires=xorg.target
After=xorg.target

[Service]
Environment=DISPLAY=:0
ExecStart=/usr/bin/python3 /opt/videoplayer/app.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=10

[Install]
WantedBy=app.service

app-recog.service 是应用程序的图像识别组件,不依赖于视频播放器:

[Unit]
Description=App Recognition Service
PartOf=app.service
After=app.service

[Service]
WorkingDirectory=/opt/recog
ExecStart=/opt/recog/recog run
ExecReload=/bin/kill -HUP $MAINPID
Restart=always
RestartSec=30

[Install]
WantedBy=app.service

app-on.target 是一个虚拟目标,一旦 app-on.timer 被触发,它就会变为活动状态,进而启用 app.service:

[Unit]
Description=App Startup Target
Conflicts=app-off.target
Wants=app.service
After=app.service
RefuseManualStart=yes

[Install]
Also=app-on.timer

app-off.target 是一个虚拟目标,一旦 app-off.timer 被触发,它就会变为活动状态,进而禁用 app.service:

[Unit]
Description=App Shutdown Target
Conflicts=app.service app-on.target
RefuseManualStart=yes

[Install]
Also=app-off.timer

app-on.timer 只是触发 app-on.target:

[Unit]
Description=App Startup Schedule

[Timer]
OnCalendar=9:00
Unit=app-on.target
Persistent=true

[Install]
WantedBy=timers.target

app-off.timer 只是触发 app-off.target:

[Unit]
Description=App Shutdown Schedule

[Timer]
OnCalendar=23:00
Unit=app-off.target
Persistent=true

[Install]
WantedBy=timers.target

这一切混乱都是由本文):

systemctl --user enable app app-mpv app-recog
systemctl --user enable --now app-on.timer app-off.timer
systemctl --user start app

应用程序开始运行,如果我检查计时器,它们都处于活动状态,并且先到的计时器将首先执行:

NEXT                         LEFT          LAST PASSED UNIT            ACTIVATES
Wed 2019-06-26 14:00:00 JST  1min 25s left n/a  n/a    app-off.timer app-off.target
Wed 2019-06-26 14:01:00 JST  2min 25s left n/a  n/a    app-on.timer  app-on.target

在触发关闭定时器后,它会停止应用程序,但是app-off.target开启目标仍然保持计划:

NEXT                         LEFT     LAST                         PASSED  UNIT            ACTIVATES
Wed 2019-06-26 14:01:00 JST  55s left n/a                          n/a     app-on.timer  app-on.target
n/a                          n/a      Wed 2019-06-26 14:00:04 JST  3ms ago app-off.timer app-off.target

当开启定时器被触发时,它会启动应用程序并禁用app-on.target,但会再次重新激活关闭定时器:

NEXT                         LEFT     LAST                         PASSED  UNIT            ACTIVATES
Thu 2019-06-27 14:00:00 JST  23h left Wed 2019-06-26 14:00:04 JST  57s ago app-off.timer app-off.target
n/a                          n/a      Wed 2019-06-26 14:01:01 JST  5ms ago app-on.timer  app-on.target

循环还在继续。我仍然怀疑这是否是配置的最佳方式,并希望听到其他建议!

相关内容