Os timers do systemd são uma alternativa moderna e poderosa ao cron para agendamento de tarefas no Linux. Eles fazem parte do sistema de inicialização systemd, presente na maioria das distribuições Linux atuais. Nesta aula, exploraremos os conceitos fundamentais dos timers, suas vantagens sobre o cron, como funcionam as units envolvidas e veremos exemplos práticos de criação e gerenciamento.

Diferentemente do cron, que é um daemon separado com sua própria sintaxe e configuração, os timers do systemd são integrados ao gerenciador de serviços. Isso significa que eles aproveitam recursos como dependências, paralelismo, logs estruturados e integração com o sistema de unidades. Além disso, os timers podem ser mais flexíveis, oferecendo opções como disparo em eventos, calendars expressivos e controle fino de ativação.

Timers vs cron

O cron é um agendador de tarefas clássico, presente no Unix desde os anos 70. Ele lê arquivos crontab e executa comandos em horários específicos, com granularidade de minuto. Apesar de simples e amplamente conhecido, o cron tem limitações: não integra bem com serviços do systemd, não oferece gerenciamento de dependências, e a execução de tarefas que precisam de um ambiente completo pode ser problemática.

Os timers do systemd, por outro lado, são units que ativam outras units (geralmente serviços) de acordo com um calendário ou eventos. Eles oferecem vantagens como:

  • Integração com o systemd: podem ser iniciados no boot, ter dependências e ser gerenciados com systemctl.
  • Logs e diagnóstico: a saída do serviço é capturada no journal, facilitando a depuração.
  • Flexibilidade: suportam expressões de calendário complexas, como 'Mon..Fri 10:00' ou '*-*-* 00,12:00:00'.
  • Eventos: podem ser acionados por eventos, como alterações em arquivos ou ativação de outros serviços.
  • Persistência: podem ser configurados para executar tarefas que foram perdidas durante o desligamento (com Persistent=true).

No entanto, o cron ainda é útil para tarefas simples e em sistemas sem systemd. A escolha entre cron e timers depende do contexto: para sistemas modernos com systemd, os timers são preferíveis.

Units básicas

Os timers do systemd são definidos em units de tipo .timer. Cada timer possui uma unit de serviço (.service) associada, que é executada quando o timer dispara. A unit de serviço define o que fazer, e a unit de timer define quando fazer.

A unit de timer contém seções como [Unit] e [Timer]. A seção [Unit] descreve o timer e pode incluir dependências, como Wants ou Requires. A seção [Timer] especifica o agendamento, com diretivas como OnCalendar, OnBootSec, OnUnitActiveSec e Persistent.

A unit de serviço associada é uma unit normal, que pode ser do tipo oneshot (executa uma vez) ou simple. O nome da unit de serviço deve corresponder ao nome do timer, exceto pela extensão. Por exemplo, um timer chamado backup.timer espera um serviço chamado backup.service.

Exemplo de estrutura básica:

# /etc/systemd/system/meu-timer.timer
[Unit]
Description=Executa meu serviço periodicamente

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

E o serviço correspondente:

# /etc/systemd/system/meu-timer.service
[Unit]
Description=Meu serviço agendado

[Service]
Type=oneshot
ExecStart=/usr/local/bin/meu-script.sh

Após criar os arquivos, é necessário recarregar o systemd (systemctl daemon-reload) e habilitar e iniciar o timer (systemctl enable --now meu-timer.timer).

Quando usar

Os timers do systemd são recomendados em várias situações:

  • Tarefas agendadas em sistemas que já usam systemd: é mais consistente gerenciar tudo com o mesmo conjunto de ferramentas.
  • Tarefas que precisam de dependências: por exemplo, esperar que um serviço esteja ativo antes de executar.
  • Tarefas que precisam de relatórios de execução: o journal do systemd captura a saída, facilitando auditoria.
  • Tarefas que devem ser executadas mesmo se o sistema estiver desligado no horário agendado: com Persistent=true, o timer executa a tarefa no próximo boot.
  • Tarefas que precisam de agendamentos complexos: como 'a cada 5 minutos durante horário comercial' ou 'no primeiro dia de cada mês, às 3h'.

Por outro lado, se você precisa de um agendamento muito simples e não quer lidar com a sintaxe de units, o cron pode ser mais direto. Além disso, em ambientes sem systemd (como containers minimalistas), o cron é a única opção.

Exemplos

Vamos criar um exemplo completo: um timer que executa um script de backup todas as noites às 2h30, com persistência para executar se o sistema estiver desligado.

Primeiro, o script de backup (em /usr/local/bin/backup.sh):

#!/bin/bash
tar -czf /backup/backup-$(date +%Y%m%d).tar.gz /dados
echo "Backup concluído em $(date)"

Torne-o executável:

chmod +x /usr/local/bin/backup.sh

Crie o serviço /etc/systemd/system/backup.service:

[Unit]
Description=Backup diário

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh

Crie o timer /etc/systemd/system/backup.timer:

[Unit]
Description=Timer para backup diário

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Agora, recarregue o systemd e ative o timer:

systemctl daemon-reload
systemctl enable --now backup.timer

Verifique o status do timer:

systemctl status backup.timer

Para listar todos os timers ativos:

systemctl list-timers

Outro exemplo: um timer que executa um serviço a cada 5 minutos durante horário comercial (segunda a sexta, 9h às 18h). A expressão de calendário seria:

OnCalendar=Mon..Fri 09..18:00/5

Isso significa de segunda a sexta, das 9h às 18h, a cada 5 minutos. É possível combinar várias diretivas OnCalendar em um timer, e o serviço será executado se qualquer uma delas corresponder.

Para testar um timer manualmente, use systemctl start backup.timer (inicia o timer, não o serviço) e systemctl start backup.service para executar o serviço diretamente.

Boas práticas

Ao usar timers do systemd, considere as seguintes práticas:

  • Nomeie as units de forma consistente: o timer e o serviço devem ter o mesmo nome base.
  • Use Persistent=true para tarefas que não podem ser perdidas, como backups.
  • Defina RandomizedDelaySec para evitar que muitos timers disparem ao mesmo tempo.
  • Monitore os timers com systemctl list-timers e verifique logs com journalctl -u backup.service.
  • Teste o serviço manualmente antes de agendar.
  • Use OnCalendar com expressões claras; consulte a documentação para a sintaxe completa.

Exercícios

  1. Crie um timer que execute um serviço chamado limpeza.service toda segunda-feira às 6h da manhã. Escreva as units completas.

    ✓ Resposta:
    # limpeza.timer
    [Unit]
    Description=Timer para limpeza semanal
    
    [Timer]
    OnCalendar=Mon *-*-* 06:00:00
    
    [Install]
    WantedBy=timers.target
    # limpeza.service
    [Unit]
    Description=Serviço de limpeza
    
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/limpeza.sh
  2. Qual é a diferença entre OnBootSec e OnUnitActiveSec? Dê um exemplo de uso de cada um.

    ✓ Resposta: OnBootSec define um tempo relativo ao boot do sistema, por exemplo OnBootSec=10min executa 10 minutos após o boot. OnUnitActiveSec define um tempo relativo à última ativação do serviço associado, por exemplo OnUnitActiveSec=1h executa 1 hora após a última execução do serviço. Exemplo: um timer que executa 5 minutos após o boot (OnBootSec=5min) e um timer que executa a cada 30 minutos após a última ativação (OnUnitActiveSec=30min).
  3. Como você verificaria se um timer está ativo e qual o próximo horário de execução?

    ✓ Resposta: Use o comando systemctl list-timers para ver todos os timers, incluindo a próxima execução. Para um timer específico, use systemctl status nome.timer.
  4. Explique o que faz a diretiva Persistent=true em um timer.

    ✓ Resposta: Persistent=true faz com que, se o sistema estiver desligado no horário em que o timer deveria disparar, o serviço seja executado imediatamente após o próximo boot. Isso é útil para tarefas como backups que não podem ser perdidas.
  5. Crie um timer que execute um serviço verificacao.service a cada 15 minutos, mas somente de segunda a sexta, das 8h às 20h. Escreva a diretiva OnCalendar correspondente.

    ✓ Resposta: OnCalendar=Mon..Fri 08..20:00/15 ou OnCalendar=Mon..Fri 08:00..20:00/15. A sintaxe correta é Mon..Fri 08..20:00/15, que significa de segunda a sexta, das 8h às 20h, a cada 15 minutos.

Referências