
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.service
y un -shutdown.service
. Los servicios se combinan en a daemon-on.target
y a daemon-off.target
, que luego son activados por daemon-on.timer
y daemon-off.timer
respectivamente.
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-timers
me 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 .target
archivos, 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 .timer
mensajes 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.target
objetivo 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!