Agendamento cron
Cron a cada 2 horas
A expressão cron para rodar a cada 2 horas é 0 */2 * * *. Ela dispara no minuto 0 de toda hora par (00:00, 02:00, 04:00, …, 22:00), 12 vezes por dia.
| Expressão | 0 */2 * * * |
|---|---|
| Execuções | 12 vezes por dia |
| OnCalendar do systemd | *-*-* 0/2:00:00 |
Como funciona
Dois campos fazem o trabalho. O */2 no campo de hora seleciona 0, 2, 4, …, 22, e o 0 no campo de minuto prende cada execução no início dessa hora. A forma longa é 0 0,2,4,6,8,10,12,14,16,18,20,22 * * *.
Para as horas ímpares, dê um ponto de partida ao passo com uma faixa: 0 1-23/2 * * * roda às 01:00, 03:00, …, 23:00. O mesmo truque muda o minuto também, por exemplo 30 1-23/2 * * *.
Como 2 divide 24, o espaçamento é sempre de 2 horas, inclusive no salto das 22:00 para as 00:00. Isso deixa de valer para passos como 5 ou 7; veja a página de a cada 6 horas.
| Campo | Valor | Significado |
|---|---|---|
| Minuto | 0 | minuto 0 (hora cheia) |
| Hora | */2 | a cada 2 horas: 0, 2, 4, …, 22 |
| Dia do mês | * | todo dia do mês |
| Mês | * | todo mês |
| Dia da semana | * | todo dia da semana |
Próximas execuções
Como no GitHub Actions sem timezone, na Vercel, na Cloudflare e no Kubernetes com timeZone "Etc/UTC".
| Execução | Seu horário | UTC |
|---|---|---|
| 1 | Calculando… | |
| 2 | ||
| 3 | ||
| 4 | ||
| 5 |
Versões prontas para colar
O mesmo agendamento em cada agendador, com o que muda em cada um.
crontab (Linux, macOS, BSD)
# m h dom mon dow command
0 */2 * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1- O cron usa o fuso horário do servidor. No cronie (Fedora, RHEL),
CRON_TZ=America/Sao_Paulonuma linha acima muda o fuso das linhas seguintes.
GitHub Actions
on:
schedule:
- cron: '0 */2 * * *'
workflow_dispatch: {}- Roda em UTC, a menos que você defina
timezone, e só no branch padrão. A documentação do GitHub avisa que execuções agendadas podem atrasar em horários de pico e que, em repositórios públicos, o agendamento é desativado após 60 dias sem atividade. - O início de cada hora é o horário de maior fila no GitHub. Se o minuto exato não importa, troque o
0por outro minuto, como17, para atrasar menos.
CronJob do Kubernetes
apiVersion: batch/v1
kind: CronJob
metadata:
name: scheduled-job
spec:
schedule: "0 */2 * * *"
timeZone: "Etc/UTC"
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: job
image: busybox:1.36
command: ["/bin/sh", "-c", "date; echo running"]spec.timeZoneé estável desde o Kubernetes 1.27; sem ele, vale o fuso do kube-controller-manager.concurrencyPolicy: Forbidpula uma execução se a anterior ainda estiver rodando.
Cron Jobs da Vercel
{
"crons": [
{ "path": "/api/cron", "schedule": "0 */2 * * *" }
]
}- A Vercel sempre usa UTC, não aceita nomes como
MONouJANe não deixa definir dia do mês e dia da semana ao mesmo tempo. - Roda mais de uma vez por dia, então precisa do plano Pro ou Enterprise. No Hobby, a documentação diz que o deploy falha com expressões que rodam mais de uma vez por dia.
Cloudflare Workers
[triggers]
crons = ["0 */2 * * *"]- Cron Triggers rodam em UTC. Mudanças podem levar até 15 minutos para se propagar pela rede da Cloudflare.
node-cron (Node.js)
import cron from 'node-cron';
// 6 campos: o primeiro (segundos) é opcional
cron.schedule('0 0 */2 * * *', async () => {
await runJob();
}, { timezone: 'UTC', noOverlap: true });- O agendamento vive dentro do processo Node: se ele cair, nada roda; se houver três réplicas, a tarefa roda três vezes.
noOverlappula um disparo enquanto o anterior não terminou.
Timer do systemd
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every 2 hours
[Timer]
OnCalendar=*-*-* 0/2:00:00
[Install]
WantedBy=timers.target
# /etc/systemd/system/job.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/job.sh
# systemctl daemon-reload && systemctl enable --now job.timer- Confira com
systemd-analyze calendar '*-*-* 0/2:00:00', que mostra a forma normalizada e a próxima execução.AccuracySecpadrão é 1min, então o disparo pode variar até um minuto.
Spring @Scheduled e Quartz
@Scheduled(cron = "0 0 */2 * * *", zone = "UTC")
public void runJob() {
// ...
}
// Quartz CronTrigger:
CronScheduleBuilder.cronSchedule("0 0 0/2 * * ?")- No Spring, o primeiro dos 6 campos são os segundos; o resto segue o cron comum (0 ou 7 = domingo).
- No Quartz, um dos campos de dia precisa ser
?, por isso o dia da semana leva?.
Armadilhas
* */2 * * * roda a cada minuto, de duas em duas horas
Com * no campo de minuto, cada hora par casa com os 60 minutos: 720 execuções por dia. O minuto precisa ser fixo, normalmente 0.
Hora par em UTC pode ser hora ímpar no seu fuso
GitHub, Vercel e Cloudflare avaliam o cron em UTC. No horário de Brasília (UTC-3) as execuções caem em horas ímpares: 0 UTC é 21h. Faz diferença se a tarefa é esperada “às 2, 4, 6” no horário local.
Tarefas de 2 horas que demoram
Uma tarefa que às vezes leva mais de 2 horas vai se sobrepor à próxima. concurrencyPolicy: Forbid no Kubernetes ou flock -n no crontab pulam a execução atrasada em vez de dobrar a carga.
Perguntas frequentes
- Qual é a expressão cron para a cada 2 horas?
- 0 */2 * * *. Ela roda às 00:00, 02:00, 04:00 e em toda hora par até as 22:00.
- Como rodar a cada 2 horas nas horas ímpares?
- 0 1-23/2 * * * roda às 01:00, 03:00, …, 23:00.
- Como rodar a cada 2 horas entre 8h e 20h?
- 0 8-20/2 * * * roda às 08:00, 10:00, 12:00, 14:00, 16:00, 18:00 e 20:00.
- 0 */2 * * * é o mesmo que 0 0-23/2 * * *?
- Sim. Um passo depois do * cobre o campo inteiro, que para horas é 0-23.
Revisado em por Arielton Oberek.