03 nov 2026 · linux, systemd, cron, automacao · 4 min
Systemd timers no lugar do cron: como migrar
Um timer systemd é um par de arquivos: um .timer que define quando disparar e um .service que define o que rodar. OnCalendar aceita expressões de calendário como o cron, Persistent=true recupera execução perdida com a máquina desligada, e o log vai para o journal em vez de virar email. A migração é trocar a linha do crontab por esses dois arquivos e rodar systemctl enable –now.
Por que trocar
O cron não sabe se a máquina estava desligada na hora marcada: a execução se perde. O log do cron depende de redirecionamento manual e de MAILTO. O timer systemd registra a última execução em disco, recupera com Persistent=true, e manda stdout e stderr para o journal, consultável com journalctl -u. A desvantagem é verbosidade: duas unidades em vez de uma linha.
O artefato: par .service e .timer
# /etc/systemd/system/backup.service
[Unit]
Description=Backup diario
[Service]
Type=oneshot
ExecStart=/opt/backup/backup.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=backup
# /etc/systemd/system/backup.timer
[Unit]
Description=Backup diario (timer)
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
RandomizedDelaySec=0
Unit=backup.service
[Install]
WantedBy=timers.target
Type=oneshot é o par natural de timer: o serviço roda e termina, e o systemd considera a ativação concluída quando o processo sai. OnCalendar=--* 03:00:00 dispara todo dia às 3h; a sintaxe é ano-mês-dia hora:minuto:segundo, com * para qualquer valor. Persistent=true grava em disco a última execução e, se o timer estava inativo na hora marcada (máquina desligada), dispara o serviço ao ligar. RandomizedDelaySec=0 desliga o atraso aleatório; útil para uma única máquina, mas em frota use um valor para não sobrecarregar o alvo. Unit= nomeia o serviço; se omitir, o systemd procura um serviço com o mesmo nome do timer.
Instalar e subir
sudo install -o root -g root -m 0644 backup.service backup.timer /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
Como verificar
systemctl list-timers --all
systemd-analyze calendar "*-*-* 03:00:00"
systemctl status backup.timer
# forcar um disparo agora:
sudo systemctl start backup.service
journalctl -u backup.service -e
list-timers mostra a próxima execução (NEXT) e a última (LAST). systemd-analyze calendar valida a expressão e imprime o próximo disparo com a contagem regressiva. Forçar o disparo com systemctl start backup.service roda o serviço uma vez sem esperar o timer; é o jeito de testar o script.
Se der errado
Timer não dispara. Causa: expressão OnCalendar inválida ou timer não ativo. Correção: valide com systemd-analyze calendar; confira systemctl status backup.timer, que deve estar active (waiting) com Trigger no futuro.
Serviço não roda. Causa: Unit= com nome errado ou arquivo .service ausente. Correção: confira o nome em backup.timer e rode systemctl daemon-reload.
Execução perdida não recuperada. Causa: Persistent só tem efeito com OnCalendar; timer monotônico (OnBootSec) não persiste. Correção: use OnCalendar para rotina de parede; para monotônico, aceite a perda.
Timer dispara só uma vez. Causa: RemainAfterExit=yes no serviço oneshot mantém o serviço ativo, e o timer não re-dispara. Correção: remova RemainAfterExit em serviço chamado por timer.
Log não aparece. Causa: StandardOutput não definido ou journal não consultado. Correção: StandardOutput=journal e StandardError=journal no .service; leia com journalctl -u backup.service.
Tabela: cron ou timer
| Recurso | cron | systemd timer |
|---|---|---|
| Sintaxe de horário | 5 campos | OnCalendar (calendário) |
| Recuperar execução perdida | não | Persistent=true |
| Log | arquivo ou email | journalctl -u |
| Dependência de outro serviço | não | After=, Requires= |
| Concorrência (não sobrepor) | flock manual | não nativo; use flock no script |
| Complexidade | uma linha | dois arquivos |
FAQ
Posso migrar todos os jobs de uma vez? Sim, mas faça um por vez e confira list-timers. Jobs que precisam de PATH específico funcionam melhor com Environment= ou EnvironmentFile.
O timer roda se a máquina estiver suspensa? Timer de calendário (OnCalendar) não dispara durante suspensão; ao acordar, se Persistent=true, recupera se a hora passou. Timer monotônico pausa com a máquina.
Como ver o próximo disparo? systemctl list-timers mostra NEXT e o tempo restante. systemd-analyze calendar “--* 03:00:00” imprime o próximo elapse.
Como desabilitar? systemctl disable –now backup.timer. O serviço pode continuar rodando se já estiver ativo; pare com systemctl stop backup.service.
Cron some do sistema? Não. Os dois convivem. Migre o que ganha com journal e recuperação; deixe cron para o que é simples.
Fontes
systemd.timer(5) e systemd.time(7), conferidos em novembro de 2026. Para serviço, systemd.service(5). Para cron, cron do jeito certo. Para logs, journalctl para achar o erro. Para segredos em arquivo, env e segredos em arquivo.