System Design/02 - Componentes/Background Jobs2 min
Schedule Driven
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Conceito
O trabalho é disparado pelo relógio: intervalo fixo, horário determinado ou expressão cron.
0 3 * * * todo dia às 3h
*/15 * * * * a cada 15 minutos
0 0 1 * * todo dia 1º do mês
Onde o agendador vive
| Opção | Nota |
|---|---|
| cron do SO | Simples; morre com a máquina, sem HA, sem visibilidade |
| Agendador da aplicação (Quartz, APScheduler) | Integrado; precisa de coordenação em cluster |
| Agendador gerenciado (EventBridge Scheduler, Cloud Scheduler) | HA embutida; dispara um serviço |
| Orquestrador (Airflow, Temporal) | Dependência entre tarefas, retry, backfill, visibilidade |
O problema do cluster
Com N instâncias da aplicação, um cron interno roda N vezes. As saídas:
- Leader Election: só o líder agenda
- Lock distribuído com TTL: quem pega o lock executa
- Agendador externo: dispara uma única chamada, e o balanceador escolhe quem atende
Trade-offs
Agendamento é previsível e cria picos. Todo job às 3h da manhã significa contenção às 3h da manhã, com o resto do dia ocioso. Espalhar horários (ou adicionar jitter) suaviza a curva.
O modelo também introduz latência estrutural: um job a cada 15 minutos significa que, no pior caso, o dado espera 15 minutos. Se o requisito é reagir rápido, o gatilho certo é Event-Driven, não um cron mais frequente — reduzir o intervalo aumenta custo linearmente sem eliminar a latência.
Duas armadilhas recorrentes:
- Execução sobreposta: o job das 3h ainda roda quando o das 3h15 começa. Sem lock, os dois competem pelo mesmo dado.
- Execução perdida: a máquina estava fora no horário. Cron não tem memória — o job simplesmente não aconteceu, e ninguém percebe. Orquestradores resolvem isso com backfill.
E, como todo job: fuso horário e horário de verão já causaram mais incidentes do que a maioria dos bugs de lógica.
Exemplo prático
Cobrança mensal de assinaturas, dia 1º às 2h. Com 50 mil assinantes, executar tudo num laço leva horas e, se falhar no meio, ninguém sabe quantos foram cobrados.
O desenho robusto separa agendamento de execução: o job das 2h apenas enfileira 50 mil tarefas (Task Queues); um pool de workers processa em paralelo, cada tarefa idempotente e com registro do que já foi cobrado.
Assim o agendador roda em segundos, a execução escala com o pool, e uma falha parcial retoma exatamente de onde parou — em vez de recomeçar e cobrar alguém duas vezes.
Relacionado
Parte de Background Jobs · roadmap.sh/system-design