Os systemd timers são a substituição moderna do cron em sistemas Linux. Eles oferecem tudo o que o cron faz — agendamento recorrente e de execução única — além de logging integrado, gerenciamento de dependências, controles de recursos e a capacidade de recuperar execuções perdidas. Se você gerencia servidores Linux, migrar do cron para systemd timers significa menos falhas silenciosas e muito mais visibilidade sobre o que suas tarefas agendadas estão fazendo.
Este guia orienta você na criação de timers do zero, na conversão de cron jobs existentes e no uso de recursos avançados como atrasos aleatórios e agendamento persistente.
Pré-requisitos
- Um sistema Linux executando systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+, ou qualquer distribuição moderna)
- Acesso root ou sudo
- Familiaridade básica com systemctl e arquivos de unit
Como os systemd Timers Funcionam
Um systemd timer consiste em dois arquivos de unit:
- Uma unit
.service— define o que executar (o comando ou script propriamente dito) - Uma unit
.timer— define quando executar (o agendamento)
A unit de timer ativa sua unit de serviço correspondente no horário programado. Ambos os arquivos devem compartilhar o mesmo nome base (por exemplo, backup.service e backup.timer), a menos que você especifique explicitamente uma unit diferente com Unit=.
Essa separação é uma vantagem fundamental sobre o cron: a unit de serviço pode ser testada independentemente, reiniciada em caso de falha e inspecionada com as ferramentas padrão do systemd.
Criando Seu Primeiro Timer
Vamos criar um timer que executa um script de limpeza todos os dias às 2:00 da manhã.
Passo 1: Criar a Unit de Serviço
sudo nano /etc/systemd/system/daily-cleanup.service
[Unit]
Description=Daily temporary file cleanup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh
O Type=oneshot informa ao systemd que este processo é executado até a conclusão e encerra — não é um daemon de longa execução. Este é o tipo correto para tarefas agendadas.
Crie o script referenciado:
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
Passo 2: Criar a Unit de 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
Diretivas principais:
| Diretiva | Finalidade |
|---|---|
OnCalendar | Agendamento baseado em calendário (como o cron) |
Persistent=true | Executa imediatamente se uma execução agendada foi perdida (por exemplo, sistema desligado) |
WantedBy=timers.target | Necessário para que o systemctl enable funcione |
Passo 3: Habilitar e Iniciar
sudo systemctl daemon-reload
sudo systemctl enable --now daily-cleanup.timer
Passo 4: Verificar
systemctl list-timers daily-cleanup.timer
Saída:
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
Teste o serviço manualmente para confirmar que funciona:
sudo systemctl start daily-cleanup.service
journalctl -u daily-cleanup.service --no-pager -n 20
Entendendo a Sintaxe do OnCalendar
A diretiva OnCalendar usa um formato flexível de expressão de calendário:
DiaDaSemana Ano-Mês-Dia Hora:Minuto:Segundo
Aqui estão os padrões mais comuns:
| Agendamento | Expressão OnCalendar |
|---|---|
| Todo dia à meia-noite | *-*-* 00:00:00 |
| Toda segunda às 9h | Mon *-*-* 09:00:00 |
| Primeiro dia de cada mês | *-*-01 00:00:00 |
| A cada 15 minutos | *-*-* *:00/15:00 |
| Dias úteis às 18h | Mon..Fri *-*-* 18:00:00 |
| Todo 1º de janeiro e julho | *-01,07-01 00:00:00 |
| A cada 2 horas | *-*-* 00/2:00:00 |
Você pode validar expressões com 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 é uma das maiores vantagens sobre o cron — você pode verificar sua expressão de agendamento antes de implantá-la.
Timers Monotônicos: Intervalos Após Eventos
Nem todos os agendamentos são baseados no relógio. Timers monotônicos disparam em relação a um evento:
[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
| Diretiva | Dispara |
|---|---|
OnBootSec | X tempo após o boot |
OnStartupSec | X tempo após o systemd iniciar |
OnUnitActiveSec | X tempo após a última ativação do timer |
OnUnitInactiveSec | X tempo após o serviço terminar |
Isso é útil para verificações de saúde, coleta de métricas ou qualquer tarefa que deve ser executada em intervalos independentemente do horário do relógio.
Exemplo — executar uma verificação de saúde a cada 5 minutos, começando 1 minuto após o boot:
[Unit]
Description=Periodic health check
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=10s
[Install]
WantedBy=timers.target
O AccuracySec=10s reduz a janela de coalescência padrão de 1 minuto, fazendo com que seu timer dispare mais próximo de exatamente a cada 5 minutos.
Recursos Avançados
Atraso Aleatório
Evite que múltiplos servidores acessem o mesmo recurso simultaneamente:
[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=900
Isso agenda a tarefa entre 3:00 e 3:15 da manhã, com o systemd escolhendo um deslocamento aleatório para cada ciclo de boot.
Controles de Recursos
Como a tarefa é executada como um serviço systemd, você pode aplicar limites de recursos:
[Service]
Type=oneshot
ExecStart=/usr/local/bin/heavy-report.sh
CPUQuota=50%
MemoryMax=512M
IOWeight=50
Nice=15
O cron não tem equivalente — você precisaria adicionar chamadas nice, ionice e ulimit dentro de cada script.
Notificação de Falha
Dispare um alerta quando uma tarefa agendada falhar:
[Unit]
Description=Database backup
OnFailure=notify-admin@%n.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
Crie o template de notificação em /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"
Convertendo Cron Jobs para systemd Timers
Aqui está uma abordagem sistemática para migrar cron jobs existentes.
Exemplo de entrada cron:
30 2 * * 1-5 /usr/local/bin/db-backup.sh
Isso executa o backup às 2:30 da manhã nos dias úteis. As units systemd equivalentes:
# /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
Referência rápida Cron para OnCalendar:
| Cron | OnCalendar |
|---|---|
0 * * * * (por hora) | *-*-* *:00:00 |
*/5 * * * * (a cada 5 min) | *-*-* *:00/5:00 |
0 0 * * 0 (semanal Dom) | Sun *-*-* 00:00:00 |
0 0 1 * * (mensal) | *-*-01 00:00:00 |
@reboot | Use OnBootSec=0 |
Após criar as units:
sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer
# Verificar
systemctl list-timers db-backup.timer
# Comentar a entrada antiga do cron
sudo crontab -e
Monitoramento e Depuração de Timers
Listar Todos os Timers Ativos
systemctl list-timers --all
Verificar Logs do Timer
journalctl -u daily-cleanup.service --since today
journalctl -u daily-cleanup.service --since "2025-12-20" --until "2025-12-23"
Depurar um Timer que Não Dispara
# Verificar status do timer
systemctl status daily-cleanup.timer
# Validar a expressão de calendário
systemd-analyze calendar "*-*-* 02:00:00"
# Verificar erros nos arquivos de unit
systemd-analyze verify /etc/systemd/system/daily-cleanup.*
# Ver todos os timers incluindo inativos
systemctl list-timers --all --no-pager
Timers Transientes para Tarefas Pontuais
Precisa executar algo uma vez em 30 minutos sem criar arquivos de unit?
systemd-run --on-active=30min /usr/local/bin/one-time-task.sh
Ou em um horário específico:
systemd-run --on-calendar="2025-12-24 15:00:00" /usr/local/bin/holiday-report.sh
Solução de Problemas
O timer mostra “n/a” em NEXT: O timer está carregado mas não habilitado. Execute systemctl enable --now <nome>.timer.
O serviço executa mas o timer não o dispara: Verifique se os nomes dos arquivos .timer e .service correspondem exatamente. Confira com systemctl cat <nome>.timer se há erros de digitação.
“Failed to parse calendar specification”: Sua sintaxe OnCalendar está incorreta. Valide com systemd-analyze calendar "sua expressão".
O timer dispara com atraso: O AccuracySec padrão é de 1 minuto. O systemd agrupa wake-ups para economizar energia. Defina AccuracySec=1s se precisar de precisão.
Execuções perdidas não são recuperadas: Você esqueceu Persistent=true na seção [Timer].
Resumo
- Os systemd timers substituem o cron com dois arquivos de unit: um
.service(o que executar) e um.timer(quando executar) OnCalendarlida com agendamentos baseados no relógio;OnBootSeceOnUnitActiveSeclidam com intervalosPersistent=truerecupera execuções perdidas após períodos de inatividadesystemd-analyze calendarpermite validar expressões de agendamento antes de implantá-las- O logging integrado via
journalctlelimina a necessidade de redirecionamento manual de logs - Controles de recursos (
CPUQuota,MemoryMax) e notificações de falha proporcionam confiabilidade de nível de produção - Todo cron job pode ser migrado para um systemd timer com mapeamento de sintaxe direto
- Use
systemd-runpara tarefas agendadas pontuais e rápidas sem criar arquivos de unit
Configurar Cron Jobs no Linux | journalctl: Consultar e Analisar Logs do Sistema Linux | Gerenciando Serviços Linux com systemctl