Por qué dejé cron#
Llevo años usando cron en mis servidores. Es simple, confiable y funciona. Pero hace poco descubrí systemd timers y no vuelvo atrás. La razón principal: logs integrados en journald, sin archivos .log dando vueltas por el sistema, y mejor control sobre qué pasa cuando el servidor arranca o reinicia.
En mi caso específico, tenía un backup que no se ejecutaba si el servidor estaba apagado a la hora programada. Con cron, simplemente se perdía. Con systemd timers y Persistent=true, la tarea se ejecuta en cuanto el servidor se enciende.
Estructura básica: .service + .timer#
Systemd necesita dos archivos:
El servicio (/etc/systemd/system/mibackup.service):
[Unit]
Description=Backup diario de datos
After=network.target
[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup.sh
StandardOutput=journal
StandardError=journalEl timer (/etc/systemd/system/mibackup.timer):
[Unit]
Description=Ejecuta backup diariamente
[Timer]
OnCalendar=daily
OnCalendar=*-*-* 03:00:00
Persistent=true
Accuracy=1min
[Install]
WantedBy=timers.targetLuego:
sudo systemctl daemon-reload
sudo systemctl enable --now mibackup.timerOnCalendar: la sintaxis que necesitas#
OnCalendar es el cron de systemd, pero más legible:
daily→ todos los días a medianocheweekly→ cada lunes a medianochehourly→ cada hora*-*-* 03:00:00→ todos los días a las 3 AMMon *-*-* 14:30:00→ cada lunes a las 14:30*-01,04,07,10-01 00:00:00→ primero de cada trimestre
Puedes combinar múltiples líneas OnCalendar:
OnCalendar=*-*-* 03:00:00
OnCalendar=*-*-* 15:00:00Esto ejecuta la tarea dos veces al día.
Persistent=true: el cambio que me convenció#
Por defecto, si tu servidor está apagado cuando se programa una tarea, systemd simplemente la ignora. Con Persistent=true, systemd remembers y ejecuta la tarea la próxima vez que arranque.
En mi servidor doméstico, esto es crítico. No siempre está encendido, y necesito garantizar que mis backups se ejecuten aunque hayan pasado horas.
[Timer]
OnCalendar=daily
Persistent=trueType=oneshot: para tareas que terminan#
El parámetro Type=oneshot en el .service indica que el proceso terminará. Es lo normal para scripts de backup, sincronización, etc.
Si usas Type=simple (el default), systemd espera que el proceso se mantenga ejecutándose. No es lo que queremos aquí.
Ver logs sin archivos externos#
Aquí está lo mejor: olvídate de >> /var/log/mibackup.log.
Los logs van directo a journald:
# Ver los últimos logs del timer
journalctl -u mibackup.service -n 50
# Ver en tiempo real
journalctl -u mibackup.service -f
# Los últimos 2 horas
journalctl -u mibackup.service --since "2 hours ago"
# Con niveles de prioridad
journalctl -u mibackup.service -p errDentro de tu script puedes loguear con echo o logger:
#!/bin/bash
logger "Iniciando backup..."
/backup/script.sh
logger "Backup completado"Todo se captura automáticamente.
Checklist de lo que hicimos#
- ✅ Creaste un
.serviceconType=oneshot - ✅ Creaste un
.timerconOnCalendaryPersistent=true - ✅ Recargaste systemd y activaste el timer
- ✅ Verificas logs con
journalctl, sin archivos de log extra
Consejo final#
Antes de depender de un timer, pruébalo manualmente:
# Ejecutar el servicio ahora
sudo systemctl start mibackup.service
# Ver qué pasó
journalctl -u mibackup.service -n 20Eso. Systemd timers no es la panacea, pero para tareas programadas en servidores modernos, es superior a cron en casi todos los aspectos. Los logs centralizados en journald, combinados con Persistent=true, hacen que sea imposible no recomendarlo.
En mi servidor doméstico, todos los backups, limpiezas de caché y sincronizaciones de datos usan timers. Cero archivos de log sueltos. Todo integrado.