TL;DR — Resumen Rápido

Aprende a programar tareas recurrentes en Linux con systemd timers. Reemplaza cron por una programación persistente, con logs y gestión de dependencias.

Los systemd timers son el reemplazo moderno de cron en sistemas Linux. Te ofrecen todo lo que hace cron — programación recurrente y de ejecución única — además de registro integrado, gestión de dependencias, control de recursos y la capacidad de recuperar ejecuciones perdidas. Si administras servidores Linux, migrar de cron a systemd timers significa menos fallos silenciosos y mucha mayor visibilidad sobre lo que hacen tus tareas programadas.

Esta guía te lleva paso a paso por la creación de timers desde cero, la conversión de trabajos de cron existentes y el uso de funcionalidades avanzadas como retrasos aleatorios y programación persistente.

Requisitos Previos

  • Un sistema Linux con systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+ o cualquier distribución moderna)
  • Acceso root o sudo
  • Familiaridad básica con systemctl y archivos de unidad

Cómo Funcionan los systemd Timers

Un systemd timer se compone de dos archivos de unidad:

  1. Una unidad .service — define qué ejecutar (el comando o script real)
  2. Una unidad .timer — define cuándo ejecutarlo (la programación)

La unidad del timer activa su unidad de servicio correspondiente según la programación. Ambos archivos deben compartir el mismo nombre base (por ejemplo, backup.service y backup.timer), a menos que especifiques explícitamente una unidad diferente con Unit=.

Esta separación es una ventaja clave sobre cron: la unidad de servicio puede probarse de forma independiente, reiniciarse en caso de fallo e inspeccionarse con las herramientas estándar de systemd.

Creación de Tu Primer Timer

Vamos a crear un timer que ejecute un script de limpieza todos los días a las 2:00 AM.

Paso 1: Crear la Unidad de Servicio

sudo nano /etc/systemd/system/daily-cleanup.service
[Unit]
Description=Daily temporary file cleanup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh

El Type=oneshot indica a systemd que este proceso se ejecuta hasta completarse y luego termina — no es un daemon de ejecución continua. Este es el tipo correcto para tareas programadas.

Crea el script al que hace referencia:

sudo tee /usr/local/bin/cleanup.sh > /dev/null << 'EOF'
#!/bin/bash
find /tmp -type f -mtime +7 -delete
find /var/log -name "*.gz" -mtime +30 -delete
echo "Cleanup completed at $(date)"
EOF
sudo chmod +x /usr/local/bin/cleanup.sh

Paso 2: Crear la Unidad del Timer

sudo nano /etc/systemd/system/daily-cleanup.timer
[Unit]
Description=Run daily cleanup at 2:00 AM

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Directivas clave:

Directiva Propósito
OnCalendar Programación basada en calendario (similar a cron)
Persistent=true Ejecutar inmediatamente si se perdió una ejecución programada (por ejemplo, si el sistema estaba apagado)
WantedBy=timers.target Necesario para que funcione systemctl enable

Paso 3: Habilitar e Iniciar

sudo systemctl daemon-reload
sudo systemctl enable --now daily-cleanup.timer

Paso 4: Verificar

systemctl list-timers daily-cleanup.timer

Salida:

NEXT                        LEFT          LAST PASSED UNIT                  ACTIVATES
Wed 2025-12-24 02:00:00 UTC 10h left      n/a  n/a   daily-cleanup.timer   daily-cleanup.service

Prueba el servicio manualmente para confirmar que funciona:

sudo systemctl start daily-cleanup.service
journalctl -u daily-cleanup.service --no-pager -n 20

Sintaxis de OnCalendar

La directiva OnCalendar utiliza un formato flexible de expresión de calendario:

DíaDeLaSemana Año-Mes-Día Hora:Minuto:Segundo

Estos son los patrones más comunes:

Programación Expresión OnCalendar
Todos los días a medianoche *-*-* 00:00:00
Cada lunes a las 9 AM Mon *-*-* 09:00:00
Primer día de cada mes *-*-01 00:00:00
Cada 15 minutos *-*-* *:00/15:00
Días laborables a las 6 PM Mon..Fri *-*-* 18:00:00
Cada 1 de enero y julio *-01,07-01 00:00:00
Cada 2 horas *-*-* 00/2:00:00

Puedes validar las expresiones con systemd-analyze calendar:

systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
  Original form: Mon..Fri *-*-* 09:00:00
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2025-12-29 09:00:00 UTC
       (in UTC): Mon 2025-12-29 09:00:00 UTC
       From now: 5 days left

Esta es una de las mayores ventajas sobre cron — puedes verificar tu expresión de programación antes de desplegarla.

Timers Monotónicos: Intervalos Después de Eventos

No todas las programaciones se basan en el reloj. Los timers monotónicos se activan en relación con un evento:

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
Directiva Se activa
OnBootSec X tiempo después del arranque
OnStartupSec X tiempo después de que inicie systemd
OnUnitActiveSec X tiempo después de la última activación del timer
OnUnitInactiveSec X tiempo después de que el servicio terminó por última vez

Esto es útil para verificaciones de salud, recopilación de métricas o cualquier tarea que deba ejecutarse a intervalos independientemente de la hora del reloj.

Ejemplo — ejecutar una verificación de salud cada 5 minutos, comenzando 1 minuto después del arranque:

[Unit]
Description=Periodic health check

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=10s

[Install]
WantedBy=timers.target

El AccuracySec=10s reduce la ventana de agrupación predeterminada de 1 minuto, de modo que tu timer se dispare más cerca de exactamente cada 5 minutos.

Funcionalidades Avanzadas

Retraso Aleatorio

Evita que múltiples servidores accedan al mismo recurso simultáneamente:

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=900

Esto programa la tarea entre las 3:00 AM y las 3:15 AM, con systemd seleccionando un desplazamiento aleatorio en cada ciclo de arranque.

Control de Recursos

Dado que la tarea se ejecuta como un servicio de systemd, puedes aplicar límites de recursos:

[Service]
Type=oneshot
ExecStart=/usr/local/bin/heavy-report.sh
CPUQuota=50%
MemoryMax=512M
IOWeight=50
Nice=15

Cron no tiene equivalente — tendrías que añadir llamadas a nice, ionice y ulimit dentro de cada script.

Notificación de Fallos

Activa una alerta cuando una tarea programada falla:

[Unit]
Description=Database backup
OnFailure=notify-admin@%n.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh

Crea la plantilla de notificación en /etc/systemd/system/notify-admin@.service:

[Unit]
Description=Send failure alert for %i

[Service]
Type=oneshot
ExecStart=/usr/local/bin/send-alert.sh "Unit %i failed on %H"

Conversión de Trabajos de Cron a systemd Timers

Aquí tienes un enfoque sistemático para migrar trabajos de cron existentes.

Ejemplo de entrada de cron:

30 2 * * 1-5 /usr/local/bin/db-backup.sh

Esto ejecuta el respaldo a las 2:30 AM en días laborables. Las unidades equivalentes de systemd:

# /etc/systemd/system/db-backup.service
[Unit]
Description=Database backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Database backup on weekday nights

[Timer]
OnCalendar=Mon..Fri *-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Referencia rápida de cron a OnCalendar:

Cron OnCalendar
0 * * * * (cada hora) *-*-* *:00:00
*/5 * * * * (cada 5 min) *-*-* *:00/5:00
0 0 * * 0 (semanal dom) Sun *-*-* 00:00:00
0 0 1 * * (mensual) *-*-01 00:00:00
@reboot Usar OnBootSec=0

Después de crear las unidades:

sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer

# Verificar
systemctl list-timers db-backup.timer

# Comentar la entrada antigua de cron
sudo crontab -e

Monitorización y Depuración de Timers

Listar Todos los Timers Activos

systemctl list-timers --all

Consultar los Logs del Timer

journalctl -u daily-cleanup.service --since today
journalctl -u daily-cleanup.service --since "2025-12-20" --until "2025-12-23"

Depurar un Timer que No se Activa

# Verificar el estado del timer
systemctl status daily-cleanup.timer

# Verificar la expresión de calendario
systemd-analyze calendar "*-*-* 02:00:00"

# Buscar errores en los archivos de unidad
systemd-analyze verify /etc/systemd/system/daily-cleanup.*

# Ver todos los timers, incluyendo los inactivos
systemctl list-timers --all --no-pager

Timers Transitorios para Tareas Puntuales

¿Necesitas ejecutar algo una sola vez en 30 minutos sin crear archivos de unidad?

systemd-run --on-active=30min /usr/local/bin/one-time-task.sh

O a una hora específica:

systemd-run --on-calendar="2025-12-24 15:00:00" /usr/local/bin/holiday-report.sh

Solución de Problemas

El timer muestra “n/a” en NEXT: El timer está cargado pero no habilitado. Ejecuta systemctl enable --now <nombre>.timer.

El servicio se ejecuta pero el timer no lo activa: Asegúrate de que los nombres de los archivos .timer y .service coincidan exactamente. Verifica con systemctl cat <nombre>.timer si hay errores tipográficos.

“Failed to parse calendar specification”: La sintaxis de tu OnCalendar es incorrecta. Valídala con systemd-analyze calendar "tu expresión".

El timer se dispara con retraso: El valor predeterminado de AccuracySec es 1 minuto. systemd agrupa las activaciones para ahorrar energía. Configura AccuracySec=1s si necesitas precisión.

Las ejecuciones perdidas no se recuperan: Olvidaste añadir Persistent=true en la sección [Timer].

Resumen

  • Los systemd timers reemplazan a cron con dos archivos de unidad: un .service (qué ejecutar) y un .timer (cuándo ejecutarlo)
  • OnCalendar gestiona las programaciones basadas en reloj; OnBootSec y OnUnitActiveSec gestionan la temporización basada en intervalos
  • Persistent=true recupera ejecuciones perdidas después de una caída del sistema
  • systemd-analyze calendar te permite validar las expresiones de programación antes de desplegarlas
  • El registro integrado mediante journalctl elimina la necesidad de redirección personalizada de logs
  • Los controles de recursos (CPUQuota, MemoryMax) y las notificaciones de fallos te ofrecen fiabilidad de nivel de producción
  • Cualquier trabajo de cron puede migrarse a un systemd timer con una conversión de sintaxis sencilla
  • Usa systemd-run para tareas programadas puntuales y rápidas sin crear archivos de unidad

Configurar Trabajos Cron en Linux | journalctl: Consultar y Analizar Logs del Sistema Linux | Gestión de Servicios Linux con systemctl

Artículos Relacionados