Alternativa ao cron: Systemd Timers

Nesse artigo você vai aprender como usar systemd timer em vez de cron para o agendamento de tarefas.

Pense no “Systemd Timer” como a versão moderna e mais inteligente do cron. Em sistemas Linux atuais (como Debian), o systemd já gerencia serviços do sistema e os timers são uma funcionalidade nativa dele.

Por que usar Systemd Timers?

  • Ambiente controlado: o serviço executado pelo timer roda em um ambiente previsível, muito mais próximo de um shell de login do que o ambiente minimalista do cron.
  • Logs superiores: toda a saída da execução é capturada pelo journald e pode ser inspecionada com journalctl, facilitando a depuração.
  • Gerenciamento como serviço: sua tarefa vira um “serviço” do sistema; você pode iniciar, parar e consultar status com o systemctl.

Visão geral

Implementaremos em duas partes: primeiro criamos um serviço que executa o script, depois um timer que agenda quando esse serviço deve rodar.

Vou usar o agendamento de geração de relatórios para o GoAccess como exemplo.

Passo 0 (opcional): Remover o trabalho do cron antigo

Para evitar execuções duplicadas, desative/remova a entrada antiga do cron (ajuste o caminho conforme seu ambiente):

sudo rm /etc/cron.d/update-goaccess.sh

Passo 1: Criar o arquivo de serviço do systemd

Crie o arquivo de unidade que descreve a tarefa a ser executada:

sudo vim /etc/systemd/system/goaccess-reporter.service

Conteúdo do arquivo:

[Unit]
Description=Gera relatórios periódicos do GoAccess para logs do Nginx

[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-goaccess.sh

Explicações:

  • Description: descrição do que o serviço faz.
  • Type=oneshot: apropriado para scripts que executam uma tarefa e encerram.
  • ExecStart: comando (seu script) a ser executado.

Passo 2: Criar o arquivo de timer do systemd

Agora crie o “agendador” que dispara o serviço acima:

sudo vim /etc/systemd/system/goaccess-reporter.timer

Conteúdo do arquivo:

[Unit]
Description=Executa o goaccess-reporter.service a cada 2 minutos

[Timer]
OnBootSec=5min
OnCalendar=*:0/2
Persistent=true

[Install]
WantedBy=timers.target

Explicações:

  • OnBootSec=5min: primeira execução 5 minutos após a inicialização.
  • OnCalendar=*:0/2: equivalente a */2 * * * * no cron (a cada 2 minutos).
  • Persistent=true: se o host estava desligado no horário programado, executa ao ligar.
  • WantedBy=timers.target: permite habilitar o timer na inicialização do sistema.

Passo 3: Recarregar, habilitar e iniciar

Carregue as unidades recém-criadas e inicie o agendamento:

sudo systemctl daemon-reload
sudo systemctl enable goaccess-reporter.timer
sudo systemctl start goaccess-reporter.timer

Como verificar se está funcionando

Listar timers (veja NEXT e LAST para confirmar o agendamento):

systemctl list-timers

Ver logs do serviço (saída das execuções do script):

journalctl -u goaccess-reporter.service

Acompanhar em tempo real:

journalctl -u goaccess-reporter.service -f

Conclusão

Os systemd timers são a forma moderna e robusta de agendar tarefas, oferecendo um ambiente mais previsível e logs integrados que eliminam os problemas típicos do cron.


Possíveis melhorias: Timer “definitivo” com nice/ionice

Após validar o funcionamento, você pode endurecer a configuração para a execução diária “oficial” com baixa prioridade de CPU e I/O, além de definir a LC_ALL explicitamente. Abaixo estão as unidades de exemplo e, em seguida, um resumo das diferenças em relação ao agendamento de teste (a cada 2 minutos).

Unidade de serviço com prioridades ajustadas

/etc/systemd/system/goaccess-reporter.service
[Unit]
Description=Gera relatórios periódicos do GoAccess para logs do Nginx

[Service]
Type=oneshot
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
Environment=LC_ALL=C.UTF-8
ExecStart=/usr/local/bin/update-goaccess.sh

Unidade de timer diária (03:17)

/etc/systemd/system/goaccess-reporter.timer
[Unit]
Description=Agendamento do goaccess-reporter.service

[Timer]
OnCalendar=*-*-* 03:17:00
Persistent=true

[Install]
WantedBy=timers.target

Aplicar e verificar

sudo systemctl daemon-reload
sudo systemctl enable --now goaccess-reporter.timer
sudo systemctl list-timers goaccess-reporter.timer

Diferenças em relação ao agendamento de teste

  • Frequência: o exemplo inicial usa OnCalendar=*:0/2 (a cada 2 minutos) para testes; a versão “definitiva” agenda uma execução diária explícita às 03:17 (OnCalendar=*-*-* 03:17:00).
  • Prioridades: adiciona Nice=10 (reduz prioridade de CPU) e IOSchedulingClass=best-effort/IOSchedulingPriority=7 (reduz prioridade de I/O), minimizando impacto em horários de backup ou maior carga.
  • Locale: define Environment=LC_ALL=C.UTF-8 para padronizar mensagens/ordenção e evitar variações de ambiente.
  • Ativação: usa enable --now para habilitar e iniciar no mesmo comando; funcionalmente equivalente a habilitar e iniciar em comandos separados.
  • OnBootSec: omitido na versão diária; você pode mantê-lo se desejar uma primeira execução “após X minutos” no boot, além do agendamento diário.

Entendendo OnCalendar=

A diretiva OnCalendar= define quando o timer dispara o serviço. Ela usa a sintaxe de “eventos de calendário” do systemd, que aceita curingas, listas, faixas e passos. Você pode escrever tanto palavras-chave (p.ex., daily, weekly) quanto formatos explícitos de data/hora.

Formatos básicos

  • Palavras-chave: minutely, hourly, daily, weekly, monthly, yearly (ou annually).
  • Forma explícita: AAAA-MM-DD HH:MM:SS, com curingas * e listas/ranges.
    Exemplo: *-*-* 03:17:00 → todos os dias às 03:17.

Listas, faixas e passos

  • Lista: Mon,Wed,Fri 08:00 → seg/qua/sex às 08:00.
  • Faixa: Mon..Fri 19:30 → de segunda a sexta às 19:30.
  • Passo: *:0/15 → a cada 15 minutos (00, 15, 30, 45).

Exemplos comuns

# A cada 2 minutos (equivalente a */2 * * * * no cron)
OnCalendar=*:0/2

# Todo dia às 03:17
OnCalendar=*-*-* 03:17:00

# Somente dias úteis às 19:30
OnCalendar=Mon..Fri 19:30

# Toda segunda-feira às 03:00
OnCalendar=Mon 03:00

# No primeiro dia de todo mês às 00:15
OnCalendar=*-*-01 00:15:00

# A cada 15 minutos, todos os dias
OnCalendar=*:0/15

Dicas práticas

  • Hora local: por padrão, o agendamento usa a hora local do sistema.
  • Testar com list-timers: após alterar o timer, rode systemctl daemon-reload e confira systemctl list-timers para verificar os próximos disparos.
  • Combinar com OnBootSec: você pode usar OnBootSec= para garantir uma primeira execução após o boot, além do OnCalendar= recorrente.

Deixe um comentário

O seu endereço de email não será publicado Campos obrigatórios são marcados *

Rolar para cima