Starten und Stoppen von systemd-Diensten mit OnCalendar für einen bestimmten Zeitraum, jeden Tag

Starten und Stoppen von systemd-Diensten mit OnCalendar für einen bestimmten Zeitraum, jeden Tag

Ich habe zwei Dienste (einen Videoplayer und einen Bilderkennungs-Daemon), die ich jeden Tag um 9 Uhr starten und um 23 Uhr beenden möchte (ebenso beim Booten, obwohl das System kontinuierlich laufen soll). Für jeden Dienst habe ich ein -startup.serviceund ein erstellt -shutdown.service. Die Dienste sind in einem daemon-on.targetund einem kombiniert, die dann jeweils von und daemon-off.targetausgelöst werden .daemon-on.timerdaemon-off.timer

Nach einigen Versuchen und Tests habe ich festgestellt, dass die Timer zunächst wie erwartet die Ziele auslösen, dann aber in den Zustand wechseln, in dem die NÄCHSTE Zeit auf „n/a“ eingestellt ist.

Das ist eine Menge Arbeit, nur um zwei Anwendungen mit einem Timer zum Laufen zu bringen. Ich bin sicher, dass etwas ganz Offensichtliches fehlt, und würde mich über jeden Tipp freuen!

mpv-startup.service startet den Videoplayer-Dienst:

[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 startet den Bilderkennungsdienst:

[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 stoppt den Videoplayer-Dienst als einmaliges Kommando

[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 stoppt den Bilderkennungsdienst mit einem einzigen Befehl:

[Unit]
Description=Recog Shutdown Service

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

[Install]
Also=daemon-off.timer

daemon-on.target kombiniert die beiden oben genannten Startdienste und wird beim Start auch mit default.target aktiviert:

[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 kombiniert die beiden oben genannten Shutdown-Dienste:

[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 ist so eingestellt, dass daemon-on.target um 9:00 Uhr ausgelöst wird:

[Unit]
Description=Daemon Startup Schedule

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

[Install]
WantedBy=timers.target

daemon-off.timer ist so eingestellt, dass daemon-off.target um 23 Uhr ausgelöst wird:

[Unit]
Description=Daemon Shutdown Schedule

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

[Install]
WantedBy=timers.target

Nachdem ich das alles untergeordnet habe, ~/.config/systemd/user/aktiviere ich sie auf die folgende Weise:

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

Dadurch wird der Daemon bei jedem Systemstart automatisch gestartet und ich erwarte, dass die Timer den Daemon je nach OnCalendar=Option starten/stoppen. An dieser Stelle systemctl --user list-timerswird mir angezeigt, dass meine beiden Timer zum richtigen Zeitpunkt ausgelöst werden (bitte beachten Sie, dass ich die Timer nur im Abstand von 3 Minuten eingestellt habe, um lange Wartezeiten zu vermeiden):

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

Der Ausschalttimer wird dann ausgelöst und mein Daemon stoppt. Nach ein paar Minuten wird der Einschalttimer ausgelöst und der Daemon startet wie vorhergesagt. Wenn ich mir die Timer jedoch noch einmal ansehe, sehe ich, dass sie zurückgesetzt wurden und die Felder NEXT/LEFT auf n/a eingestellt sind und den Daemon nie wieder auslösen werden. Was ist hier das Problem?

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

Antwort1

Nach etwas mehr Suche und dem Lesen der Manpages von systemd gelang es mir, die Dinge ein wenig zu vereinfachen und auch das gewünschte Verhalten meiner Dienste zu erreichen.

Erstens habe ich Fehler gemacht, als ich [Service]-Abschnitte in meine .targetDateien eingefügt habe, was keinen Sinn ergab. Zweitens habe ich eine PartOf=Anweisung entdeckt, mit der ich eine Anwendung auf oberster Ebene mit Videoplayer und Erkennungsdiensten als Komponenten erstellen konnte. Und schließlich Conflicts=konnte ich mit der Option meine Anwendung mit zwei Zielen starten/stoppen, die miteinander in Konflikt stehen. Die .timeran diese Ziele angehängten s wechseln dann zwischeneinander und deaktivieren oder aktivieren meine Anwendungskette und die jeweiligen in Konflikt stehenden s .targets. Das Ergebnis ist immer noch in 7 Dateien enthalten, was mehr ist, als ich verwalten möchte, aber es funktioniert wie gewünscht.

app.service ist die Anwendung der obersten Ebene. Obwohl es sich um einen Dummy handelt, könnte hier etwas anderes ausgeführt werden:

[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 ist die Videoplayer-Komponente der App und hängt daher ebenfalls von xorg ab:

[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 ist die Bilderkennungskomponente der App und ist nicht vom Videoplayer abhängig:

[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 ist ein virtuelles Ziel, es wird aktiv, sobald der app-on.timer ausgelöst wird und aktiviert wiederum den 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 ist ein virtuelles Ziel, es wird aktiv, sobald der app-off.timer ausgelöst wird und deaktiviert wiederum den app.service:

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

[Install]
Also=app-off.timer

app-on.timer löst einfach app-on.target aus:

[Unit]
Description=App Startup Schedule

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

[Install]
WantedBy=timers.target

app-off.timer löst einfach app-off.target aus:

[Unit]
Description=App Shutdown Schedule

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

[Install]
WantedBy=timers.target

All dieses Durcheinander zu ermöglichen (mit Hilfe vonDieser Artikel):

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

Die Anwendung wird gestartet. Wenn ich die Timer überprüfe, sind beide aktiv. Was zuerst eintritt, wird zuerst ausgeführt:

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

Nachdem der Ausschalttimer ausgelöst wurde, wird die Anwendung gestoppt, das app-off.targetEinschaltziel bleibt jedoch geplant:

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

Wenn der Einschalttimer ausgelöst wird, startet er die Anwendung und deaktiviert den app-on.target, aktiviert den Ausschalttimer jedoch erneut:

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

Und der Zyklus geht weiter. Ich bezweifle immer noch, dass dies die beste Konfigurationsmethode ist, und würde gerne andere Vorschläge hören!

verwandte Informationen