OnCalendar を使用して、毎日一定期間 systemd サービスを開始および停止する

OnCalendar を使用して、毎日一定期間 systemd サービスを開始および停止する

毎日午前 9 時に開始し、午後 23 時に終了する 2 つのサービス (ビデオ プレーヤーと画像認識デーモン) があります (システムは継続的に実行されますが、起動時にも実行されます)。各サービスに対して、 と を作成しました-startup.service-shutdown.serviceこれらのサービスは と に結合され、daemon-on.targetそれぞれとdaemon-off.targetによってトリガーされます。daemon-on.timerdaemon-off.timer

数回の試行とテストの後、タイマーは最初は期待どおりにターゲットをトリガーしますが、NEXT 時間が n/a に設定された状態になることがわかりました。

タイマーを使用して 2 つのアプリケーションを実行するだけでも、かなりの作業が必要です。明らかに何かが欠けていると思いますので、ヒントがあれば教えてください。

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 は上記の 2 つの起動サービスを組み合わせ、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 は上記の 2 つのシャットダウン サービスを組み合わせます。

[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 は、23pm に 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-timers2 つのタイマーが適切な時間にトリガーされることがわかります (長時間待機する必要がないように、タイマーを 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=オプションを使用することで、互いに競合する 2 つのターゲットを使用してアプリケーションを開始/停止できます。.timerこれらのターゲットにアタッチされた は、互いに切り替わり、アプリケーション チェーンとそれぞれの競合する を無効または有効にします.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

そして、このサイクルは続きます。これが設定の最善の方法であるかどうかはまだ疑問なので、他の提案もぜひ聞きたいです。

関連情報