
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.service
und ein erstellt -shutdown.service
. Die Dienste sind in einem daemon-on.target
und einem kombiniert, die dann jeweils von und daemon-off.target
ausgelöst werden .daemon-on.timer
daemon-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-timers
wird 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 .target
Dateien 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 .timer
an 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.target
Einschaltziel 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!