Ir para o conteúdo
AZ Tools

Como os agendamentos cron realmente funcionam

Uma expressão cron são cinco números pequenos que decidem quando sua tarefa roda — e um número surpreendente de incidentes em produção começa por lê-los errado. Este guia cobre a sintaxe, a única regra que se comporta ao contrário do que se lê, as armadilhas de fuso horário e os hábitos que mantêm um agendamento confiável quando ninguém está olhando.

Os cinco campos

O cron padrão recebe cinco campos, nesta ordem: minuto (0–59), hora (0–23), dia do mês (1–31), mês (1–12) e dia da semana (0–6, sendo 0 domingo). Cada campo aceita um valor único, uma lista (`1,15`), um intervalo (`9-17`), um passo (`*/15`) ou `*` para "todos". Assim, `0 9 * * 1-5` significa nove da manhã, de segunda a sexta.

Passos se aplicam ao intervalo que vem antes deles, e é por isso que `*/15` no campo de minutos significa "0, 15, 30, 45" e não "a cada quinze minutos a partir de quando a tarefa foi criada". Um agendamento dispara quando a hora atual casa com o padrão: o cron não acompanha intervalos, ele observa o relógio.

Dia do mês e dia da semana são OU, não E

Esta é a regra que surpreende todo mundo. Quando os campos de dia do mês e de dia da semana estão *ambos* restritos, o cron roda a tarefa quando *qualquer um* deles casa — não quando os dois casam. Portanto `0 0 13 * 5` não é "sexta-feira 13": roda no dia 13 de todo mês e também em toda sexta-feira.

O comportamento só aparece quando os dois campos estão restritos. Se um deles é `*`, o outro simplesmente decide. Para obter uma interseção de verdade você precisa de uma verificação dentro da própria tarefa — cheque a data no início do script e saia cedo — porque a expressão não consegue expressar isso.

Em qual relógio ele roda?

Uma expressão cron não carrega fuso horário. O agendamento é interpretado no fuso que o executor usar: o fuso local da máquina no crond clássico, UTC na maioria dos agendadores gerenciados e sistemas de CI. Os mesmos cinco campos significam, então, momentos reais diferentes conforme onde são implantados — é assim que um relatório "da meia-noite" acaba chegando no meio da tarde.

Se o executor usa um fuso com horário de verão, duas vezes por ano o agendamento falha de uma entre duas formas. Na noite em que o relógio adianta, uma tarefa agendada dentro da hora pulada simplesmente não roda. Na noite em que atrasa, a hora repetida pode rodá-la duas vezes. Agendar em UTC evita as duas coisas, ao custo de a hora local escorregar uma hora ao longo do ano — escolha deliberadamente com qual falha você consegue conviver.

Extensões, apelidos e o sexto campo

Muitos agendadores estendem a sintaxe clássica, e de forma incompatível. Expressões no estilo Quartz acrescentam um campo inicial de segundos, então uma expressão de seis campos significa algo totalmente diferente de uma de cinco e um agendamento copiado pode disparar sessenta vezes mais. Algumas variantes acrescentam `L` (último), `W` (dia útil mais próximo) e `#` (enésimo dia da semana do mês); outras aceitam `?` no lugar de `*` nos campos de dia.

A maioria das implementações também aceita apelidos: `@hourly`, `@daily`, `@weekly`, `@monthly`, `@yearly` e às vezes `@reboot`. São mais claros que os equivalentes numéricos quando servem, mas escondem o minuto exato — `@daily` é meia-noite, que é também quando todas as outras tarefas `@daily` da máquina começam.

Projetar agendamentos que sobrevivem

Presuma que alguma execução será perdida, repetida ou sobreposta, e projete a tarefa para que nada disso corrompa dados. Torne-a idempotente para que uma execução dupla seja inofensiva, pegue um lock para que uma execução lenta não se sobreponha à seguinte e registre o que foi processado para que uma execução perdida possa recuperar em vez de deixar uma lacuna silenciosa.

Espalhe os agendamentos. Tudo que estiver em `0 0 * * *` começa junto, e num host compartilhado essa avalanche foi você quem causou. Escolha um minuto quebrado, escalone tarefas relacionadas e acrescente um pequeno atraso aleatório no início de qualquer coisa que bata numa API compartilhada. Por fim, alerte quando a tarefa *não* tiver rodado: um agendamento que para de disparar em silêncio parece exatamente igual a um que não tinha nada a fazer.

  • `*/15 * * * *` — a cada quinze minutos, nos quartos de hora.
  • `0 9 * * 1-5` — 09:00 em dias úteis, no fuso do executor.
  • `0 0 13 * 5` — dia 13 *ou* qualquer sexta, não sexta-feira 13.
  • `0 3 1 * *` — 03:00 do primeiro dia do mês.

Ferramentas relacionadas