06 - Timers (Substituindo cron)
video: https://youtu.be/... no frontmatter da nota.Os temporizadores do systemd — identificados pela extensão .timer — representam a evolução arquitetural para o agendamento de tarefas temporais e execução de rotinas periódicas no ecossistema Linux. Historicamente, essa responsabilidade era monopolizada pelo cron (e suas variantes como vixie-cron, cronie e anacron), um daemon independente que consulta a cada minuto a tabela /etc/crontab e dispara comandos via subshell sem integração direta com o estado do sistema.
A transição do cron para as unidades .timer substitui a execução cega de comandos isolados pela orquestração declarativa de processos atrelados ao Grafo Acíclico Dirigido (DAG) do PID 1. Um arquivo .timer não executa scripts diretamente; ele atua como um gatilho de eventos que monitora relógios internos do kernel e dispara a ativação de uma unidade correspondente (tipicamente um .service de mesmo nome base).
1. A Ruptura com o Paradigma do Cron
O modelo tradicional do cron sofre de limitações estruturais severas quando aplicado a infraestruturas modernas e ambientes de alta concorrência:
- Ausência de Rastreamento de Processos: Quando o
crondispara um script, ele executa umfork()simples. Se o script gerar subprocessos (workers ou threads filhas) e sofrer uma terminação anormal, os subprocessos tornam-se órfãos no espaço de usuário, consumindo memória e I/O sem que ocrontenha visibilidade do estado real. - Gestão de Recursos Cega: O
cronnão possui capacidade nativa para impor cotas de CPU, RAM ou limitar a largura de banda de I/O de disco para os trabalhos agendados. Se três rotinas pesadas coincidirem na mesma janela de tempo (ex:00:00), o servidor sofre uma tempestade de I/O (I/O storm) que pode causar indisponibilidade total de serviços críticos. - Logs Fragmentados e Desconectados: O
cronredireciona nativamente a saída das tarefas para o subsistema local de e-mails (mailx//var/spool/mail) ou exige o redirecionamento manual de saídas para arquivos de texto (>> /var/log/backup.log 2>&1). Não há vinculação direta entre o evento de tempo e o histórico de execução da aplicação. - Tratamento de Perda de Janela de Execução: Se a máquina estivesse desligada no exato minuto em que uma tarefa do
crondeveria rodar, a execução era simplesmente perdida. A solução para isso exigia a instalação de outro daemon paralelo (anacron), com sintaxe e comportamentos totalmente distintos.
Os systemd timers resolvem integralmente essa dívida técnica. Como o .timer ativa um .service real, a tarefa agendada herda automaticamente:
- Isolamento via Cgroups: Limitações estritas de recursos (
CPUQuota=,MemoryMax=,IOWeight=). - Rastreamento Inviolável de Processos: Eliminação total de processos zumbis ou órfãos através de encerramento via cgroup.
- Coleta de Telemetria Nativa: Integração total com o
journald, permitindo inspeção individualizada do histórico de execução (journalctl -u meu-backup.service). - Resiliência contra Desligamentos: Controle nativo de recuperação de tarefas perdidas em janelas de tempo offline via persistent de estado em disco.
2. A Invocação por Par Duplo (Timer + Service)
A arquitetura de agendamento do systemd exige estritamente a criação de duas unidades independentes, porém vinculadas:
┌───────────────────────────┐ ┌───────────────────────────┐
│ backup.timer │ │ backup.service │
├───────────────────────────┤ ├───────────────────────────┤
│ [Timer] │ │ [Service] │
│ OnCalendar=*-*-* 02:00:00 ┼──────────►│ Type=oneshot │
│ Unit=backup.service │ (Dispara) │ ExecStart=/usr/bin/backup │
└───────────────────────────┘ └───────────────────────────┘
- A Unidade de Gatilho (
.timer): Contém a lógica de monitoramento de relógio (quando rodar) e a indicação de qual unidade deve ser disparada. - A Unidade de Execução (
.service): Define como o processo deve rodar (diretivasExecStart=, limites de memória, usuário de execuçãoUser=, variáveis de ambiente).
Por convenção de nomenclatura, se o arquivo .timer for nomeado backup.timer, ele procurará e ativará automaticamente o arquivo backup.service no mesmo diretório de carga. Se o serviço possuir um nome diferente, o arquivo .timer deve declarar explicitamente a diretiva Unit=outro-nome.service na seção [Timer].
3. Tipologia dos Relógios: Monotônicos vs. Tempo Real
O systemd provê duas categorias completamente distintas de temporizadores, que mapeiam chamadas de sistema e relógios internos diferentes mantidos pelo kernel Linux (clock_gettime).
3.1. Temporizadores Monotônicos (Monotonic Timers)
Os temporizadores monotônicos medem o tempo corrido a partir de um evento de estado do sistema operativo. Eles utilizam o relógio CLOCK_MONOTONIC do kernel, que é um contador estritamente crescente e imune a alterações manuais no relógio da máquina ou ajustes de fusos horários e sincronizações via NTP (Network Time Protocol).
Todas as diretivas monotônicas aceitam unidades de tempo expressas em segundos (s), minutos (m), horas (h), dias (d) ou semanas (w).
OnActiveSec=: Computa o tempo a partir do momento exato em que a própria unidade.timerfoi ativada na memória RAM (viasystemctl startou durante o boot).OnBootSec=: Computa o tempo a partir do momento em que o kernel Linux iniciou o processo de inicialização do hardware.OnStartupSec=: Computa o tempo a partir do instante em que o PID 1 (systemd) foi instanciado no espaço de usuário.OnUnitActiveSec=: Computa o tempo a partir da última vez em que a unidade.serviceassociada transitou para o estadoactive.OnUnitInactiveSec=: Computa o tempo a partir do momento em que a unidade.serviceassociada finalizou sua execução e retornou ao estadoinactive.
Exemplo de Temporizador Monotônomo Recorrente:
Para criar um job de limpeza que roda 15 minutos após o boot do sistema e, a partir daí, executa novamente a cada 2 horas exatas:
# /etc/systemd/system/limpeza-cache.timer
[Unit]
Description=Gatilho de Limpeza de Cache Periódica
[Timer]
OnBootSec=15m
OnUnitInactiveSec=2h
[Install]
WantedBy=timers.target
3.2. Temporizadores de Tempo Real (Realtime / Calendar Timers)
Os temporizadores de tempo real medem o tempo absoluto do calendário humano (relógio de parede / Wall Clock), utilizando o relógio CLOCK_REALTIME do kernel. Eles são configurados através da diretiva OnCalendar=.
A sintaxe das expressões de calendário no systemd substitui a notação opaca do cron (* * * * *) por uma especificação textual rica e declarativa:
DiaDaSemana Ano-Mês-Dia Hora:Minuto:Segundo
Regras de Construção de Expressões OnCalendar=:
- Coringas (
*): Representa qualquer valor válido para aquele campo. - Faixas (
..): Define intervalos contínuos (ex:Mon..Fripara dias úteis, ou01..15para os primeiros quinze dias do mês). - Listas (
,): Agrupa múltiplos valores específicos (ex:08,12,16:00:00para rodar às 8h, 12h e 16h). - Repetições Periódicas (
/): Define incrementos (ex:*:0/15:00para executar a cada 15 minutos).
Matriz Comparativa de Expressões de Tempo Real:
Expressão OnCalendar= |
Equivalente Conceitual | Descrição de Execução |
|---|---|---|
*-*-* 00:00:00 |
@daily ou 0 0 * * * |
Executa todos os dias à meia-noite. |
Mon..Fri *-*-* 03:00:00 |
0 3 * * 1-5 |
Executa de segunda a sexta-feira, rigorosamente às 03:00:00 AM. |
*-*-01 04:00:00 |
@monthly ou 0 4 1 * * |
Executa no primeiro dia de cada mês, às 04:00:00 AM. |
*-*-15..31 Fri 23:00:00 |
N/A (Complexo no Cron) | Executa na última sexta-feira do mês (se cair entre o dia 15 e 31) às 23:00:00. |
hourly |
@hourly |
Atalho interno para *-*-* *:00:00 (no início de cada hora). |
weekly |
@weekly |
Atalho interno para Mon *-*-* 00:00:00 (toda segunda-feira à meia-noite). |
4. Recursos Avançados de Orquestração Temporal
A especificação .timer expõe diretivas avançadas que resolvem gargalos clássicos de concorrência e resiliência em data centers e clusters.
4.1. Persistência e Recuperação de Janela (Persistent=true)
Se o servidor for desligado antes da janela de execução de um temporizador OnCalendar= (por exemplo, uma rotina configurada para as 03:00 AM em uma estação de trabalho que é desenergizada à noite), o cron tradicional simplesmente ignoraria a execução.
A diretiva Persistent=true resolve isso ativando um mecanismo de marcação de estado em disco:
- Sempre que o serviço atrelado ao timer finaliza com sucesso, o
systemdatualiza o timestamp de execução no arquivo/var/lib/systemd/timers/stamp-nome_do_timer.timer. - No próximo ciclo de boot, quando o
systemdcarrega o arquivo.timer, ele lê a marcação em/var/lib/systemd/timers/. - Se o tempo atual for maior do que o tempo configurado na expressão
OnCalendar=e a última execução gravada for anterior ao evento perdido, o PID 1 dispara o serviço associado imediatamente.
4.2. Pulverização Aleatória de Carga (RandomizedDelaySec=)
Em arquiteturas de computação em nuvem, virtualização corporativa ou gerenciamento de configurações (como Ansible/Puppet), implantar o mesmo arquivo de agendamento em 5.000 instâncias virtuais rodando sob o mesmo barramento de armazenamento SAN/NVMe cria tempestades de I/O destrutivas se todas as máquinas tentarem ler e escrever no disco no mesmo segundo (00:00:00).
A diretiva RandomizedDelaySec=15m instrui o systemd a calcular um desvio aleatório entre 0 e o tempo estipulado (15 minutos) para cada máquina individualmente:
- O timer determina a janela de execução para as 02:00 AM.
- Cada nó calculará um offset único baseado no seu
machine-id(ex: a máquina A rodará às 02:03:12, a máquina B às 02:11:45). - A carga de CPU e I/O no hipervisor é distribuída suavemente ao longo da janela, prevenindo gargalos de infraestrutura.
4.3. Precisão do Temporizador (AccuracySec=)
Por padrão, para otimizar o consumo de energia e evitar acordar o processador do estado de suspensão (C-states) a todo segundo, o systemd alinha os temporizadores em janelas de coalescência de eventos de 1 minuto (AccuracySec=1min).
Para tarefas críticas de alta precisão que exigem execução temporal estrita em milissegundos, o administrador pode sobrescrever essa margem:
[Timer]
OnCalendar=*-*-* *:00:00
# Força o disparo com precisão de 1 microssegundo
AccuracySec=1us
5. Inspeção, Gerenciamento e Diagnóstico da CLI
O gerenciamento de temporizadores é integrado à CLI unificada do systemctl.
5.1. Listagem dos Temporizadores Ativos (systemctl list-timers)
O comando systemctl list-timers varre a memória do PID 1 e desenha uma tabela consolidada sobre o estado de todas as unidades .timer carregadas no sistema:
systemctl list-timers
Saída Típica do Comando:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Wed 2026-10-14 18:00:00 -03 2h 5min left Wed 2026-10-14 17:00:00 -03 54min ago logrotate.timer logrotate.service
Thu 2026-10-15 00:00:00 -03 8h left Wed 2026-10-14 00:00:00 -03 17h ago fstrim.timer fstrim.service
Thu 2026-10-15 03:10:00 -03 11h left Thu 2026-10-08 03:10:00 -03 6 days ago apt-daily-upgrade.timer apt-daily-upgrade.service
3 timers listed.
Análise das Colunas do Relatório:
NEXT: A data e hora exatas da próxima execução agendada no relógio do sistema.LEFT: A contagem regressiva temporal restante até o próximo disparo.LAST: A data e hora exatas da última vez que o temporizador disparou o serviço associado.PASSED: O tempo decorrido desde a última execução com sucesso.UNIT: O nome do arquivo de unidade.timerresponsável pelo monitoramento.ACTIVATES: A unidade.servicede destino que será invocada no instante do disparo.
5.2. Teste de Expressões e Validação de Sintaxe (systemd-analyze calendar)
Para evitar erros de sintaxe ao escrever expressões complexas na diretiva OnCalendar=, o systemd provê a ferramenta de análise sintática systemd-analyze calendar.
Ao passar uma expressão de tempo como argumento, o utilitário analisa a string, valida a sintaxe, exibe a forma normalizada e calcula as próximas iterações em que a tarefa será disparada:
systemd-analyze calendar "Fri..Sun *-*-15..31 22:00:00"
Saída de Validação da CLI:
Normalized form: Fri..Sun *-*-15..31 22:00:00
Next elapse: Fri 2026-10-16 22:00:00 -03
(in UTC): Sat 2026-10-17 01:00:00 UTC
From now: 2 days left
5.3. Fluxo de Instalação e Ativação de um Timer
Para criar e ativar um novo agendamento no sistema, a sequência operacional correta é:
- Criar o arquivo de serviço
/etc/systemd/system/meu-job.service:
[Unit]
Description=Execução de Script de Manutenção
[Service]
Type=oneshot
ExecStart=/usr/local/bin/manutencao.sh
User=root
- Criar o arquivo de temporizador
/etc/systemd/system/meu-job.timer:
[Unit]
Description=Gatilho Diário para Script de Manutenção
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
- Recarregar a máquina de estados do PID 1 para parsear as novas unidades em RAM:
systemctl daemon-reload
- Habilitar e iniciar o temporizador (opera sobre o
.timer, não sobre o.service):
systemctl enable --now meu-job.timer
6. Quadro Comparativo: cron vs. systemd.timer
| Propriedade Arquitetural | Sistema Tradicional (cron) |
Sistema Moderno (systemd.timer) |
|---|---|---|
| Daemon Responsável | Processo isolado (crond). |
PID 1 (systemd). |
| Granularidade Mínima | 1 Minuto. | 1 Microsegundo (AccuracySec=1us). |
| Rastreamento de Processos | Não possui (Filhos órfãos escapam do rastreamento). | Total via cgroups (Rastreia e destrói subprocessos). |
| Coleta de Logs | Saída redirecionada para arquivos de texto manuais ou e-mail. | Integrada nativamente ao Journald (journalctl -u service). |
| Controle de Recursos | Inexistente (Risco de travar o servidor por I/O). | Suporta cotas estritas de CPU, RAM e I/O via cgroups no .service. |
| Recuperação de Boots Offline | Requer ferramenta externa paralela (anacron). |
Nativa via diretiva Persistent=true. |
| Desvio Aleatório de Carga | Requer injeção de comandos sleep $RANDOM em scripts. |
Nativa via diretiva RandomizedDelaySec=. |
| Execução Sob Demanda (Teste) | Requer edição do arquivo crontab ou execução manual do script. | Testável via systemctl start meu-job.service sem alterar a agenda. |