Se você trabalha com Linux, provavelmente já usou o Cron para agendar tarefas periódicas. Ele é o "velho padrão de guerra", mas, apesar de funcional, o Cron possui algumas limitações ou "manias" que podem complicar sistemas modernos.
Neste artigo, vamos explorar por que o systemd timers é uma alternativa superior e como você pode portar seus scripts de forma simples.
O Problema com o Cron
O Cron não é um padrão unificado. Dependendo da sua distribuição, você pode estar lidando com o Cron tradicional, anacron, fcron ou jobber, e cada um se comporta de maneira ligeiramente diferente. Além disso, gerenciar logs e falhas no Cron geralmente envolve redirecionamentos manuais de saída (>> /var/log/cron.log 2>&1), o que raramente é uma solução "limpa".
Por que migrar para systemd Timers?
Diferente do Cron, os timers são unidades do systemd. Isso significa que eles herdam todo o poder do ecossistema que já gerencia seus serviços.
Principais Benefícios:
- Logging Nativo: Esqueça o redirecionamento manual. Tudo vai automaticamente para o journald, com colunas de tempo e metadados já inclusos.
- Dependências Inteligentes: Você pode configurar uma tarefa para rodar apenas se outra unidade estiver ativa ou reagir a mudanças no hardware.
- Controle de Recursos: É fácil definir limites de CPU, memória (OOM score) e acesso à rede diretamente no arquivo de unidade.
- Tratamento de Falhas: Suporte nativo para
OnFailure, permitindo disparar alertas ou scripts de recuperação se algo der errado. - Execução Persistente: Com
Persistent=true, se a máquina estava desligada no horário agendado, o job roda assim que ela voltar a ligar comportamento parecido com o do anacron, mas nativo. É o argumento decisivo para quem usa laptop ou VPS que não fica ligado 24/7.
Mão na Massa: Portando um Cron Job
No Cron, o agendamento e a ação ficam na mesma linha. O systemd divide isso em dois arquivos: um arquivo de serviço e um arquivo de timer.
1. O Script (A Ação)
Crie um script em /usr/local/bin/meu-script.sh e torne-o executável:
sudo chmod +x /usr/local/bin/meu-script.sh
2. O Arquivo de Serviço (.service)
Crie este arquivo em /etc/systemd/system/meu-script.service. Ele define o que rodar.
[Unit]
Description=Meu Script de Automação
[Service]
Type=oneshot
ExecStart=/usr/local/bin/meu-script.sh
Repare no Type=oneshot. Para um script que roda, faz o seu trabalho e termina (o caso típico de um cron job), esse é o tipo correto. O padrão é Type=simple, que funciona, mas considera o serviço "ativo" enquanto o processo estiver vivo — o que atrapalha a leitura de status e as dependências para tarefas de execução curta.
3. O Arquivo de Timer (.timer)
Crie este arquivo em /etc/systemd/system/meu-script.timer. Ele define quando o serviço será disparado.
[Unit]
Description=Agenda a execução do meu script
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=300
Unit=meu-script.service
[Install]
WantedBy=timers.target
- OnCalendar: Define o agendamento. Aqui,
dailyequivale a todo dia à meia-noite. Você pode ser mais explícito, como*-*-* 03:00:00para rodar às 3h da manhã. - Persistent: Recupera execuções perdidas enquanto a máquina esteve desligada.
- RandomizedDelaySec: Espalha a execução dentro de uma janela aleatória (aqui, até 5 minutos). É o jeito certo de evitar que vários timers disparem exatamente no mesmo segundo e sobrecarreguem o sistema.
> Curiosidade: ao contrário do Cron, o
OnCalendaraceita granularidade abaixo de um minuto. Algo comoOnCalendar=*:*:0/30dispara a cada 30 segundos — uma coisa que o Cron tradicional simplesmente não faz.
Atenção à precisão: por padrão, os timers não disparam no segundo exato. O systemd usa o
AccuracySec(padrão de 1 minuto) para agrupar disparos próximos e economizar "wakeups" da CPU, ou seja, o timer pode rodar em qualquer momento dentro dessa janela. Para a maioria das tarefas isso é irrelevante, mas se você precisa de precisão ao segundo (como no exemplo dos 30 segundos acima), adicioneAccuracySec=1usna seção[Timer]. O trade-off é abrir mão da economia de energia.
Como Ativar e Testar
Após criar os arquivos, você precisa notificar o systemd:
- Recarregar o daemon:
sudo systemctl daemon-reload. - Habilitar e iniciar de uma vez:
sudo systemctl enable --now meu-script.timer. > Atenção: você habilita e inicia o.timer, nunca o.service. É o timer que controla quando o serviço será disparado.
Ferramenta Bônus: systemd-analyze
Você pode testar seus formatos de tempo antes de salvar:
systemd-analyze calendar "daily"
Isso mostrará exatamente os próximos horários em que seu script será disparado, eliminando o "adivinho" do Cron.
Monitorando Logs
Para acompanhar a execução em tempo real, use o comando:
journalctl -fu meu-script.service
Você também pode listar todos os timers ativos e ver quando cada um vai disparar a próxima vez:
systemctl list-timers
Conclusão
Embora exija dois arquivos em vez de uma linha, a granularidade e a segurança dos systemd timers compensam o esforço inicial. Recursos como persistência, controle de recursos e logging nativo fazem dele uma modernização essencial para qualquer fluxo de trabalho robusto no Linux.
Referencias:
Top comments (2)
OnCalendar timers aren't minute-precise out of the box, systemd batches them with a default AccuracySec of one minute to save wakeups. Has that bitten anyone migrating a cron job that assumed exact-second timing?
@valentynkit Great point, this is exactly the kind of gotcha worth calling out. You're right that AccuracySec defaults to 1 minute, so systemd is free to fire anywhere within that window to batch wakeups.
For jobs that genuinely need second-level precision, you can set AccuracySec=1us in the [Timer] section to force systemd to honor the exact time. The trade-off is losing the power savings from batching, so it's only worth it when the timing actually matters.
Honestly, for most cron jobs the 1-minute window is a non-issue but it definitely bites if you're migrating something that assumed exact-second scheduling. Thanks for raising it, I'll add a note about AccuracySec to the article.