Agendamento cron
Cron a cada 30 segundos
O cron padrão não faz isso: a menor unidade dele é o minuto. A saída comum são duas linhas no crontab, * * * * * job.sh e * * * * * sleep 30; job.sh; um timer do systemd com OnCalendar=*:*:0/30 ou um agendador de 6 campos como o node-cron (*/30 * * * * *) resolve de forma nativa.
| Expressão | Não existe no cron padrão de 5 campos |
|---|---|
| Execuções | 2.880 vezes por dia |
| OnCalendar do systemd | *:*:0/30 |
Como funciona
O daemon do cron acorda uma vez por minuto, compara cada linha do crontab com o minuto, a hora, o dia, o mês e o dia da semana atuais e dispara o que bater. O formato de 5 campos não tem segundos, então nada na expressão consegue dizer “no segundo 30”. É um limite do projeto, não um recurso que falta na sua versão: cronie, o cron do Debian, o crond do BusyBox e os agendadores hospedados trabalham em minutos inteiros.
O truque das duas linhas funciona porque as duas entradas disparam no início do minuto e a segunda espera 30 segundos antes de fazer qualquer coisa. Serve bem para verificações leves. Complica quando o tempo de execução varia, porque o intervalo deixa de ser 30 segundos e duas cópias podem rodar juntas.
Se a máquina é sua, o timer do systemd é a resposta limpa: OnCalendar=*:*:0/30 quer dizer segundos 0 e 30 de todo minuto, e AccuracySec=1s impede o systemd de agrupar os disparos. Dentro de uma aplicação, um agendador com campo de segundos (node-cron, Spring, Quartz) ou um loop simples com sleep é mais direto que o cron.
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)
# cron can’t go below one minute: start two copies per minute,
# the second one 30 seconds late.
* * * * * /usr/local/bin/job.sh
* * * * * sleep 30; /usr/local/bin/job.sh- As duas linhas disparam no segundo 0 de cada minuto; o
sleep 30atrasa a segunda cópia. Se a tarefa demora alguns segundos, o intervalo fica irregular, e se passa de 30 segundos as cópias se sobrepõem. Coloqueflock -n /tmp/job.lockantes do comando para evitar isso.
GitHub Actions(Não suportado)
- Não dá: o menor intervalo de agendamento no GitHub Actions é 5 minutos.
CronJob do Kubernetes(Não suportado)
- Não dá:
spec.scheduleusa cron de 5 campos, então o mínimo é um minuto, e subir um Pod a cada 30 segundos seria desperdício de qualquer forma. Use um Deployment com um loop.
Cron Jobs da Vercel(Não suportado)
- Não dá: as expressões da Vercel têm 5 campos, e o mais frequente é uma vez por minuto nos planos Pro e Enterprise.
Cloudflare Workers(Não suportado)
- Não dá com Cron Triggers, que usam 5 campos. Um alarme de Durable Object que se reagenda para daqui a 30 segundos resolve.
node-cron (Node.js)
import cron from 'node-cron';
// second 0 and second 30 of every minute
cron.schedule('*/30 * * * * *', async () => {
await runJob();
}, { noOverlap: true });- Com seis campos, o primeiro são os segundos, então
*/30 * * * * *dispara em :00 e :30.noOverlap: truepula um disparo se o anterior não terminou.
Timer do systemd
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every 30 seconds
[Timer]
OnCalendar=*:*:0/30
AccuracySec=1s
[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/30', que mostra a forma normalizada e a próxima execução.AccuracySecpadrão é 1min, então o disparo pode variar até um minuto. - O
AccuracySec=1sé essencial: com o padrão de 1min, o systemd pode agrupar os disparos e o timer de 30 segundos acaba virando algo perto de um por minuto.
Spring @Scheduled e Quartz
@Scheduled(cron = "*/30 * * * * *")
public void runJob() { }
// Or, for a fixed period instead of clock-aligned times:
@Scheduled(fixedRate = 30, timeUnit = TimeUnit.SECONDS)
// Quartz CronTrigger:
CronScheduleBuilder.cronSchedule("0/30 * * * * ?")- Spring e Quartz têm campo de segundos, então basta uma linha. O
fixedRateconta a partir do início da aplicação, não do relógio.
Armadilhas
Seis campos significam coisas diferentes em cada ferramenta
node-cron e Spring colocam os segundos primeiro, então */30 * * * * * é a cada 30 segundos neles. Cole a mesma string num crontab de 5 campos e ela é rejeitada; tire o primeiro campo e * * * * * vira a cada minuto. O Quartz também começa pelos segundos, mas exige ? num campo de dia: 0/30 * * * * ?.
Sobreposição quando a execução passa de 30 segundos
Uma linha do cron não sabe da outra. Se a tarefa leva 40 segundos, a próxima começa antes de ela terminar. Proteja o comando com flock -n /tmp/job.lock job.sh para a cópia atrasada sair em vez de se acumular.
Subir um processo duas vezes por minuto custa caro
São 2.880 processos por dia, cada um lendo configuração e abrindo conexões do zero. Se a tarefa verifica se há trabalho, um worker contínuo que dorme 30 segundos entre as voltas, ou uma fila, costuma sair mais barato e reagir mais rápido.
Perguntas frequentes
- Dá para rodar um crontab a cada 30 segundos?
- Não com uma linha só. O formato de 5 campos não tem segundos, então o mais frequente é a cada minuto. Use duas linhas, a segunda com sleep 30 na frente, ou passe para um timer do systemd ou um agendador com campo de segundos.
- Qual é o timer do systemd para cada 30 segundos?
- OnCalendar=*:*:0/30 com AccuracySec=1s. Sem o AccuracySec, o systemd pode atrasar cada disparo em até um minuto para agrupar despertares.
- */30 * * * * é a cada 30 segundos?
- Não. No crontab de 5 campos o primeiro campo é o minuto, então */30 * * * * roda nos minutos 0 e 30, a cada meia hora. Só agendadores de 6 campos, como node-cron e Spring, leem */30 * * * * * como segundos.
- GitHub Actions ou Vercel rodam a cada 30 segundos?
- Não. O menor intervalo do GitHub é 5 minutos e o da Vercel é 1 minuto (planos Pro e Enterprise). Os dois usam cron de 5 campos.
Revisado em por Arielton Oberek.