Reemplazando cron con Systemd Timer

Este es uno de los capítulos del tutorial Trabajando con Systemd. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.

En el capítulo anterior de este tutorial sobre crear un servicio con Systemd te expliqué como podías crear tu primer servicio. Realmente es una solución muy sencilla y cómoda para tener una aplicación funcionando en segundo plano. O simplemente una servicio que quisieras ejecutarlo en según que condiciones. No solo esto, sino que además te permite iniciar el servicio directamente cuando se inicie tu sistema, sin necesidad de que tu te preocupes de ello. Pero, y si en lugar de que se inicie con el sistema, lo que ¿quieres es que tu servicio se inicie en un día y a una hora determinada?¿Y si quieres que se ejecute de forma periódica? La solución Systemd timer

La automatización de tareas pasa precisamente por programarlas. De esta manera, una operación tan tediosa como realizar una copia de seguridad, deja de ser un problema. Tu ya no te tienes que preocupar por hacerlo, Systemd se encarga de ello. Evidentemente te tienes que preocupar de que esa copia se haya hecho, y para ello, puedes crear medidas de seguridad adicionales. Por ejemplo, puedes establecer, que en caso de que falle, te envíe un correo electrónico o un mensaje a tu Telegram.

Reemplazando cron con Systemd Timer

Cron vs Systemd Timer

Aunque cron es el programador de tareas por excelencia, lo cierto es que los timers de Systemd son una excelente alternativa. Pero no solo esto sino que además presentan ciertas ventajas frente a cron.

  • cron no es un estándar. La mayoría de las distribuciones tratan cron como si fuera un estándar, pero actualmente casi ninguna utiliza el mismo demonio cron. Son pequeñas diferencias, pero lo suficientes para que puedas tener problemas. Por el contrario Systemd es un estándar.
  • Mientras que cron tiene todas las tareas en un único archivo llamado crontab, Systemd, tiene un archivo por timer. El problema de cron, es la coordinación entre los diferentes servicios. Otro problema son los cambios en cron, que llega un punto que no sabes cual es la última versión. Un timer de Systemd utilizará un archivo para describir la programación del servicio, es decir, para describir la tarea y un segundo para describir el servicio en si mismo.

Un sencillo ejemplo de un Systemd timer

Para demostrar como se puede crear una tarea utilizando un Systemd timer, te voy a mostrar un sencillo ejemplo. Este ejemplo está compuesto de tres piezas. El ejecutable, el servicio y la tarea. Como verás tanto el servicio como la tarea tienen el mismo nombre de archivo y distinta extensión. Así uno es test.service y el otro es test.timer. Si no lo haces así, tendrás que declarar en el timer el servicio que quieres ejecutar.

Para no complicar el ejemplo, nuestro ejecutable, lo único que hace es escribir la fecha actual en un archivo `registro.log tal y como puedes ver a continuación.

#!/bin/bash
DATE=`date '+%Y-%m-%d %H:%M:%S'`echo "$DATE" >> /home/lorenzo/registro.log

El archivo del servicio /home/lorenzo/.config/systemd/user/test.service, es tan sencillo como sigue. Va a ser un servicio que solo se ejecuta una vez.

[Unit]
Description=Una prueba

[Service]
Type=oneshot
ExecStart=/bin/bash /home/lorenzo/test.sh

Por último, el archivo del timer/home/lorenzo/.config/systemd/user/test.timer. Con el timer establecemos que se va a ejecutar una vez cada minuto nuestro servicio.

 
[Unit]
Description=Runs every 1 minutes test.sh

[Timer]
OnCalendar=*:0/1

[Install]
WantedBy=timers.target

Otro ejemplo de ejecutable que nos permite cambiar el fondo de pantalla de forma aleatoria entre todos las imángenes que se encuentran el directorio de fondos de pantalla.

#!/bin/bash

walls_dir=/usr/share/backgrounds
selection=$(find $walls_dir -type f -name "*.jpg" -o -name "*.png" | shuf -n1)
gsettings set org.gnome.desktop.background picture-uri "file://$selection"

El archivo del servicio /home/lorenzo/.config/systemd/user/gbc.service

[Unit]
Description=Rotate GNOME background

[Service]
Type=oneshot
Environment=DISPLAY=:0
ExecStart=/bin/bash /home/lorenzo/gbc.sh

El archivo del timer /home/lorenzo/.config/systemd/user/gbc.timer

[Unit]
Description=Rotate GNOME wallpaper timer

[Timer]
OnCalendar=*:0/1

[Install]
WantedBy=timers.target

Si modificas el archivo del servicio ya sea test.service o gbc.service tienes que recargar la configuración del gestor de Systemd ejecutando systemctl --user daemon-reload. Esta orden lo que hace es ejecutar todos los generadores recargar todos los archivos deunidades y recrear por completo el arbol de dependencials.

Como sucede con cualquier otro servicio, los timers funcionan de la misma forma. Así, para habilitar el servicio al inicio del sistema, tenemos que ejecutar,

systemctl --user enable test.timer
systemctl --user enable gbc.timer

Para iniciar cualquiera los timers, ejecutaremos, para cada uno de ellos, las siguientes órdenes,

systemctl --user start test.timer
systemctl --user start gbc.timer

Mientras que para detenerlos,

systemctl --user stop test.timer
systemctl --user stop gbc.timer

Configurando la fecha de ejecución de la tarea

Se pueden programar dos tipos. Un primero que lo que hará será ejecutarse al iniciarse el equipo. Por ejemplo, el siguiente systemd timer está configurado para ejecutar nuestro servicio 15 minutos después del arranque y a partir de ese momento, una vez a la semana siempre y cuando el equipo esté en funcionamiento.

[Unit]
Description=Una prueba se ejecuta 15 min después del arranque y una vez a la semana.

[Timer]
OnBootSec=15min
OnUnitActiveSec=1w

[Install]
WantedBy=timers.target

El segundo de los tipos de timerse ejecuta en una fecha especificada. El formato de la fecha es DiaDeLaSemana Año-Mes-Día Hora:Minuto:Segundo. Se puede utilizar,

  • * para indicar cualquier valor
  • valores separados por comas para indicar un listado de posibles
  • .. para indicar un rango continuo de valores
  • / seguido por un valor. Esto indica que se ejecutará en ese valor y en los múltiplos correspondientes. Así *:0/10 indica que se ejecutará cada 10 minutos.
  • ~ indica el último día del mes. Por ejemplo, *-02~03 indica el tercer último mes de febrero.

Algunos ejemplos,

  • OnCalendar=Mon,Tue *-*-01..04 12:00:00 indica que se ejecutará los cuatro primeros días de cada mes las 12 horas siempre y cuando sea lunes o martes.
  • OnCalendar=*-*-* 20:00:00 se ejecutará todos los días a las 20 horas.
  • OnCalendar=Mon..Fri *-*-* 20:00:00 se ejecutará de lunes a vierne a las 20 horas.
  • OnCalendar=*-*-* *:0/15 ó OnCalendar=*:0/15 se ejecutará cada 15 minutos

También se puede utilizar algunos atajos,

  • OnCalendar=minutely → *-*-* *:*:00
  • OnCalendar=hourly → *-*-* *:00:00
  • OnCalendar=daily → *-*-* 00:00:00
  • OnCalendar=monthly → *-*-01 00:00:00
  • OnCalendar=weekly → Mon *-*-* 00:00:00
  • OnCalendar=yearly → *-01-01 00:00:00
  • OnCalendar=quarterly → *-01,04,07,10-01 00:00:00
  • OnCalendar=semiannually → *-01,07-01 00:00:00

Conclusión

Sinceramente me he quedado enamorado de esta solución para programar tareas, que, al menos en mi caso, está reemplazando por completo a cron.


Más información,

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *