Iniciar y detener servicios systemd con OnCalendar por un período de tiempo, todos los días

Iniciar y detener servicios systemd con OnCalendar por un período de tiempo, todos los días

Tengo dos servicios (un reproductor de vídeo y un demonio de reconocimiento de imágenes) que quiero iniciar a las 9 a. m. y terminar de ejecutarse a las 23 p. m. todos los días (así como al arrancar, aunque el sistema estará funcionando continuamente). Para cada servicio creé un -startup.servicey un -shutdown.service. Los servicios se combinan en a daemon-on.targety a daemon-off.target, que luego son activados por daemon-on.timery daemon-off.timerrespectivamente.

Después de algunos intentos y pruebas, descubrí que los temporizadores inicialmente activan los objetivos como se esperaba, pero pasan al estado con la PRÓXIMA hora configurada en n/a.

Es una gran cantidad de trabajo solo para ejecutar dos aplicaciones con un temporizador. ¡Estoy seguro de que le falta algo obvio y agradecería cualquier consejo!

mpv-startup.service inicia el servicio del reproductor de video:

[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 inicia el servicio de reconocimiento de imágenes:

[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 detiene el servicio del reproductor de video como un comando de una sola vez

[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 detiene el servicio de reconocimiento de imágenes como un comando de una sola vez:

[Unit]
Description=Recog Shutdown Service

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

[Install]
Also=daemon-off.timer

daemon-on.target combina dos servicios de inicio anteriores y también se habilita al inicio con 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 combina dos servicios de apagado anteriores:

[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 está configurado para activar daemon-on.target a las 9 a. m.:

[Unit]
Description=Daemon Startup Schedule

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

[Install]
WantedBy=timers.target

daemon-off.timer está configurado para activar daemon-off.target a las 23 p. m.:

[Unit]
Description=Daemon Shutdown Schedule

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

[Install]
WantedBy=timers.target

Después de colocar todo esto debajo ~/.config/systemd/user/los habilito de la siguiente manera:

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

Lo que iniciará automáticamente el demonio en cada arranque y aquí espero que los temporizadores inicien/detengan el demonio según la OnCalendar=opción. En este punto, systemctl --user list-timersme muestra que mis dos temporizadores se activarán en los momentos correctos (tenga en cuenta que configuré los temporizadores con solo 3 minutos de diferencia para ahorrar tiempo de espera):

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

Luego se activa el temporizador de apagado y mi demonio se detiene, después de unos minutos se activa el temporizador de encendido y el demonio se inicia según lo previsto. Sin embargo, al mirar los temporizadores nuevamente, veo que se reiniciaron y que los campos SIGUIENTE/IZQUIERDA están configurados en n/a, y nunca volverán a activar el demonio. Cuál es el problema aquí?

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

Respuesta1

Después de buscar un poco más y leer las páginas de manual de systemd logré simplificar un poco las cosas y también obtener el comportamiento deseado de mis servicios.

En primer lugar, cometí errores al colocar secciones [Servicio] en mis .targetarchivos, lo cual no tenía sentido. En segundo lugar, descubrí una PartOf=declaración que me permitió crear una aplicación de alto nivel con reproductor de video y servicios de reconocimiento como componentes. Y, por último, al usar Conflicts=la opción podría iniciar/detener mi aplicación usando dos objetivos que entran en conflicto entre sí. Los .timermensajes de correo electrónico adjuntos a esos objetivos alternarán entre sí, deshabilitando o habilitando mi cadena de aplicaciones y los respectivos conflictos .targets. El resultado todavía está contenido en 7 archivos, que es más de lo que me gustaría mantener, pero funciona según sea necesario.

app.service es la aplicación de nivel superior, aunque es ficticia, podría ejecutar algo más:

[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 es el componente del reproductor de vídeo de la aplicación y, por lo tanto, también depende de 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 es el componente de reconocimiento de imágenes de la aplicación y no depende del reproductor de vídeo:

[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 es un objetivo virtual, se activa tan pronto como se activa app-on.timer y, a su vez, habilita 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 es un objetivo virtual, se activa tan pronto como se activa app-off.timer y, a su vez, desactiva app.service:

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

[Install]
Also=app-off.timer

app-on.timer simplemente activa 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 simplemente activa app-off.target:

[Unit]
Description=App Shutdown Schedule

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

[Install]
WantedBy=timers.target

Permitir todo este lío (con la ayuda deEste artículo):

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

La aplicación comienza a ejecutarse y si reviso los temporizadores, ambos están activos y el que llegue primero se ejecutará primero:

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

Después de que se activa el temporizador de apagado, detiene la aplicación y el app-off.targetobjetivo permanece programado:

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

Cuando se activa el temporizador de encendido, inicia la aplicación y desactiva el app-on.target, pero reactiva el temporizador de apagado nuevamente:

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

Y el ciclo continúa. ¡Todavía dudo si esta es la mejor manera de configurar esto y me encantaría escuchar otras sugerencias!

información relacionada