Skip to content

Agendamento cron

Cron toda semana

Para rodar um cron uma vez por semana, use @weekly ou a expansão dele, 0 0 * * 0, que dispara às 00:00 de todo domingo. Qualquer dia serve: 0 0 * * 1 é semanal às segundas.

Toda semana
Expressão0 0 * * 0
Macro@weekly
Execuções52 vezes em 2027
OnCalendar do systemdSun *-*-* 00:00:00

Como funciona

O crontab(5) define @weekly como 0 0 * * 0, e a documentação de CronJob do Kubernetes traz a mesma expansão. O @weekly do Spring é o equivalente de 6 campos, 0 0 0 * * 0. O GitHub Actions não aceita @weekly, segundo a própria documentação, e Vercel e Cloudflare documentam só os cinco campos, então escreva os campos.

O dia da semana é escolha, não regra. Domingo só é o padrão por causa de como o @weekly foi definido. O systemd escolheu segunda para a palavra weekly, e as tarefas semanais do anacron rodam a cada 7 dias contados da última execução, não num dia fixo.

Semanal também quer dizer que você tem uma semana até perceber que a tarefa quebrou. Registre a execução, alerte em caso de falha, ou crie uma verificação que reclame se a tarefa não der sinal em 8 dias.

Explicação campo a campo
CampoValorSignificado
Minuto0minuto 0 (hora cheia)
Hora0hora 0 (0h)
Dia do mês*todo dia do mês
Mês*todo mês
Dia da semana0domingo

Próximas execuções

Relógio do agendador

Como no GitHub Actions sem timezone, na Vercel, na Cloudflare e no Kubernetes com timeZone "Etc/UTC".

Próximas execuções, calculadas no seu navegador a partir de agora
ExecuçãoSeu horárioUTC
1Calculando… 
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)

crontab -e
# m h dom mon dow  command
0 0 * * 0 /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_Paulo numa linha acima muda o fuso das linhas seguintes.

GitHub Actions

.github/workflows/scheduled.yml
on:
  schedule:
    - cron: '0 0 * * 0'
      # timezone: 'America/Sao_Paulo'  # opcional; sem ele, UTC
  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 0 por outro minuto, como 17, para atrasar menos.
  • Com timezone num fuso que tem horário de verão, um horário que não existe no dia da mudança é adiado para o próximo horário válido (2:30 vira 3:00, segundo a documentação).

CronJob do Kubernetes

cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: scheduled-job
spec:
  schedule: "0 0 * * 0"
  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: Forbid pula uma execução se a anterior ainda estiver rodando.

Cron Jobs da Vercel

vercel.json
{
  "crons": [
    { "path": "/api/cron", "schedule": "0 0 * * 0" }
  ]
}
  • A Vercel sempre usa UTC, não aceita nomes como MON ou JAN e não deixa definir dia do mês e dia da semana ao mesmo tempo.
  • Cabe no plano Hobby, mas lá a precisão é por hora: o disparo pode acontecer em qualquer minuto dentro da hora agendada.

Cloudflare Workers

wrangler.toml
[triggers]
crons = ["0 0 * * SUN"]
  • Cron Triggers rodam em UTC. Mudanças podem levar até 15 minutos para se propagar pela rede da Cloudflare.
  • Na Cloudflare, os dias da semana vão de 1 = domingo a 7 = sábado, diferente do cron comum. Por isso o exemplo usa nomes (MON, SUN), que não têm ambiguidade.

node-cron (Node.js)

scheduler.js
import cron from 'node-cron';

// 6 campos: o primeiro (segundos) é opcional
cron.schedule('0 0 0 * * 0', 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. noOverlap pula um disparo enquanto o anterior não terminou.

Timer do systemd

job.timer + job.service
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service weekly, Sunday at midnight

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

[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 'Sun *-*-* 00:00:00', que mostra a forma normalizada e a próxima execução. AccuracySec padrão é 1min, então o disparo pode variar até um minuto.
  • Persistent=true roda a tarefa assim que a máquina liga se o horário passou com ela desligada, algo que o cron não faz.
  • O OnCalendar=weekly do próprio systemd significa Mon *-*-* 00:00:00, segunda e não domingo. O timer acima escreve domingo por extenso para bater com o @weekly do cron.

Spring @Scheduled e Quartz

Java
@Scheduled(cron = "0 0 0 * * 0", zone = "UTC")
public void runJob() {
    // ...
}

// Quartz CronTrigger:
CronScheduleBuilder.cronSchedule("0 0 0 ? * SUN")
  • 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 ?, e os dias da semana vão de 1 = domingo a 7 = sábado; por isso o exemplo usa nomes.

Armadilhas

O weekly do systemd é segunda

systemd-analyze calendar weekly normaliza para Mon *-*-* 00:00:00. Levar uma entrada @weekly do crontab para um timer com OnCalendar=weekly muda o dia.

A cada duas semanas não cabe no cron

Não existe campo de número da semana. Rode semanalmente e teste a semana ISO: [ $(( $(date +\%V) \% 2 )) -eq 0 ] && job.sh. Anos com 53 semanas ISO colocam a semana 53 e a semana 1 lado a lado, as duas ímpares, então o ritmo quebra ali: uma tarefa de semanas pares espera três semanas, uma de semanas ímpares roda duas semanas seguidas.

Execução semanal com a máquina desligada

Se o servidor está fora do ar no domingo 00:00, a execução se perde até a semana seguinte. O anacron ou o Persistent=true do systemd recuperam no boot.

Perguntas frequentes

Qual é a expressão cron para uma vez por semana?
0 0 * * 0, ou @weekly, roda à meia-noite de todo domingo. Mude o último campo para escolher outro dia.
Em que dia o @weekly roda?
Domingo às 00:00 no crontab, no Kubernetes e no Spring. A palavra weekly do systemd é segunda às 00:00.
Como rodar um cron a cada duas semanas?
Agende semanalmente e deixe o comando verificar o número da semana, por exemplo [ $(( $(date +\%V) \% 2 )) -eq 0 ] && job.sh.
A cada 7 dias é o mesmo que toda semana?
No cron, sim, desde que você agende pelo dia da semana. */7 no campo de dia do mês não é a mesma coisa: roda nos dias 1, 8, 15, 22 e 29 e reinicia todo mês.

Revisado em por Arielton Oberek.