Expressões cron: os cinco campos, com exemplos
Uma expressão cron são cinco campos separados por espaço que dizem quando uma tarefa roda: minuto, hora, dia do mês, mês, dia da semana. Lendo da esquerda para a direita, 30 2 * * 1 significa no minuto 30 da hora 2, em qualquer dia de qualquer mês, se esse dia for uma segunda-feira.
Os cinco campos
Toda linha de cron Unix padrão começa com os mesmos cinco campos, seguidos do comando a executar.
* * * * * command to run
| | | | |
| | | | +-- day of week (0-7, 0 and 7 both mean Sunday, or SUN-SAT)
| | | +---- month (1-12, or JAN-DEC)
| | +------ day of month (1-31)
| +-------- hour (0-23)
+---------- minute (0-59)
Um campo contém uma de quatro coisas: um asterisco, que significa todos os valores, um número único, uma lista ou um intervalo. As horas usam relógio de 24 horas, sem AM nem PM, então 18h é 18. Domingo é ao mesmo tempo 0 e 7 porque sistemas diferentes discordaram historicamente, e o cron aceita os dois.
Alguns agendadores acrescentam campos. O Quartz, usado por muitos frameworks Java, coloca um campo de segundos na frente e um ano opcional no fim, então uma expressão de seis ou sete campos copiada de uma referência do Quartz não vai funcionar em uma crontab de Linux. Confira para qual variante você está escrevendo antes de copiar uma expressão de qualquer lugar.
Os caracteres especiais
*corresponde a todos os valores do campo.* * * * *roda a cada minuto.,lista valores.0 8,13,20 * * *roda às 08:00, 13:00 e 20:00.-define um intervalo.0 9-17 * * *roda na hora cheia das 09:00 às 17:00./define um passo dentro de um intervalo.*/15 * * * *roda nos minutos 0, 15, 30 e 45. Dá para combinar com um intervalo:0 9-17/2 * * *roda às 9, 11, 13, 15 e 17.- Nomes.
MONaSUNeJANaDECfuncionam nos dois últimos campos e são mais legíveis que números. Não podem ser usados dentro de um passo.
Outros quatro caracteres aparecem o tempo todo em tutoriais e não existem no cron padrão. L para último dia, W para o dia útil mais próximo, # para o enésimo dia da semana no mês e ? no lugar de um asterisco são extensões do Quartz. Uma expressão como 0 0 L * * será rejeitada por uma crontab de Linux. Para rodar algo no último dia do mês ali, rode diariamente e deixe o comando decidir:
0 0 * * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end.sh
Repare nas barras invertidas dessa linha. O sinal de porcentagem tem um significado especial em uma crontab, que é o quinto erro da lista abaixo.
O cron também aceita seis atalhos no lugar dos cinco campos: @yearly (também escrito @annually), @monthly, @weekly, @daily (também @midnight), @hourly e @reboot, que roda uma vez quando o cron inicia, e não pelo relógio. @reboot não é suportado em todo lugar.
Agendamentos comuns
| Quando você quer que rode | Expressão |
|---|---|
| A cada minuto | * * * * * |
| A cada 5 minutos | */5 * * * * |
| A cada 30 minutos | 0,30 * * * * |
| Toda hora, na hora cheia | 0 * * * * |
| A cada 2 horas | 0 */2 * * * |
| Todo dia à meia-noite | 0 0 * * * |
| Todo dia às 02:30 | 30 2 * * * |
| Duas vezes por dia, 08:00 e 20:00 | 0 8,20 * * * |
| Dias úteis às 09:00 | 0 9 * * MON-FRI |
| De hora em hora no horário comercial, dias úteis | 0 9-17 * * MON-FRI |
| Toda segunda-feira às 07:00 | 0 7 * * MON |
| Todo domingo às 03:15 | 15 3 * * SUN |
| Dia 1 do mês às 06:00 | 0 6 1 * * |
| Trimestral, dia 1 de janeiro, abril, julho e outubro | 0 0 1 1,4,7,10 * |
Erros que colocam a tarefa na hora errada
- Preencher os dois campos de dia. Esse pega todo mundo. Quando dia do mês e dia da semana estão os dois preenchidos com algo diferente de um asterisco, o cron roda a tarefa quando qualquer um dos dois corresponde, não os dois juntos.
0 0 13 * FRIroda todo dia 13 e toda sexta-feira, não na sexta-feira 13. - Um passo que não divide o intervalo.
*/7 * * * *dispara nos minutos 0, 7, 14, 21, 28, 35, 42, 49 e 56, e então recomeça no 0. O intervalo na virada da hora é de quatro minutos, não sete. A mesma armadilha vale para*/40no campo de minuto e para qualquer passo que não seja divisor de 60. - Colocar o passo no campo errado.
*/2 * * * *é a cada dois minutos.0 */2 * * *é a cada duas horas. Esquecer o0inicial transforma uma tarefa de hora em hora em uma que roda 30 vezes mais. - Presumir o ambiente. O cron dá à tarefa um ambiente mínimo, normalmente pouco mais que
PATH=/usr/bin:/bineSHELL=/bin/sh. Um script que funciona no seu shell falha no cron porque chama algo em/usr/local/bin. Use caminhos absolutos para o comando e dentro dele. - Um sinal de porcentagem sem escape. Em uma crontab,
%vira uma quebra de linha e tudo depois da primeira delas é entregue ao comando como entrada padrão. Umdate +%Y-%m-%ddentro de uma linha de crontab precisa ser escritodate +\%Y-\%m-\%d. - Ignorar a saída. Tudo que a tarefa imprime é enviado por e-mail ao dono da crontab, e em uma máquina sem correio configurado isso é descartado. Mande para um lugar que você vá ler:
0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 - Deixar execuções se sobreporem. O cron inicia a próxima execução no horário marcado, tenha a anterior terminado ou não. Envolva tarefas longas em um lock:
*/5 * * * * flock -n /tmp/sync.lock /usr/local/bin/sync.sh - Esquecer as mudanças de horário. O cron usa o horário local da máquina. Nos dias em que os relógios mudam, a hora em torno das 02:00 ou não existe ou acontece duas vezes, então uma tarefa agendada dentro dela pode ser pulada ou rodar duas vezes, dependendo da implementação do cron. Coloque os servidores em UTC, ou agende fora dessa janela.
- Digitar
crontab -r. Isso apaga a crontab inteira sem pedir confirmação, e fica a uma tecla de distância decrontab -e. Mantenha a crontab em controle de versão e instale-a a partir de um arquivo.
Verifique de fora
Uma expressão que é aceita não é a mesma coisa que uma tarefa que rodou. Verifique as duas, na máquina e depois fora dela.
Na máquina, confirme o que está instalado, o que o relógio diz e se o cron iniciou a tarefa:
crontab -l
timedatectl
grep CRON /var/log/syslog | tail -20
journalctl -u cron -u crond --since "2 hours ago"
A linha de log prova que o cron disparou o comando. Ela não diz nada sobre o comando ter dado certo, e é por isso que o redirecionamento para um arquivo de log citado nos erros acima importa.
Depois verifique o resultado como um usuário faria, de fora do servidor. A maioria das tarefas agendadas existe para mudar algo observável: um feed que deveria trazer a data de hoje, um sitemap que deveria ter sido reescrito, uma exportação que deveria ter aparecido. Peça o arquivo e leia os cabeçalhos:
curl -sI https://example.com/exports/daily.json
curl -s https://example.com/health/last-run
O cabeçalho Last-Modified diz se o arquivo está atualizado, e faz isso sem acesso ao shell. Rodar a mesma requisição de várias localizações com a verificação HTTP separa uma tarefa que não rodou de uma página que está em cache em uma borda de uma região e desatualizada só ali. Essa diferença é invisível a partir de um único curl no próprio servidor.
Saber quando uma tarefa agendada para de rodar
Uma tarefa cron que para de rodar não produz nada para se notar. Não há página de erro nem requisição que falhe, então nada dispara alerta a menos que algo esteja observando a ausência. O que você monitora é o efeito da tarefa, não a tarefa: um arquivo de status que ela reescreve, um carimbo de tempo que ela publica, um endpoint que informa a última execução bem-sucedida. Uma verificação programada contra esse endpoint transforma uma falha silenciosa em uma notificação, e a HostTracker envia essas notificações por e-mail, SMS, chamada de voz, Slack, Telegram e outros canais, em 13 tipos de monitoramento. Como configurar uma delas está em o guia da verificação HTTP, o resto dos guias de diagnóstico está no grupo de correções, e a lista completa de tipos de verificação está na página de recursos.