Laravel

Como evitar duplicidade de processamento em jobs

Duplicidade em job é uma das coisas mais comuns (e mais perigosas) em produção. E não adianta lutar contra isso achando que “não vai acontecer”. Vai. Worker cai, timeout estoura, conexão oscila, retry acontece, o mesmo evento chega duas vezes, o deploy reinicia processo no meio… e pronto: job roda de novo.

O objetivo não é “garantir que nunca execute duas vezes”. O objetivo é garantir que executar duas vezes não cause dano.

Abaixo estão as estratégias que realmente funcionam em projetos Laravel médios e grandes.


1) Torne o job idempotente (regra número 1)

Idempotência significa: rodar uma vez ou dez vezes dá o mesmo resultado final.

Isso é o que separa um job saudável de um job que vai te dar dor de cabeça.

Exemplos práticos:

  • “enviar notificação”: marque como enviado e não envie novamente se já estiver enviado.
  • “gerar fatura”: use uma chave única e não crie duas faturas para o mesmo evento.
  • “sincronizar pedido”: atualize o registro existente em vez de criar um novo.

Em termos práticos, idempotência quase sempre vira: checar estado antes de executar e persistir o estado depois.


2) Use chave idempotente por evento (event_id / request_id)

Toda vez que o seu sistema gera um job, ele deveria ter um identificador estável do evento.

Exemplo:

  • event_id do webhook recebido
  • message_id da sua tabela
  • order_id + status (depende do caso)
  • um UUID de “processamento” gerado quando o evento nasceu

Aí você registra algo como:

  • “event_id X já foi processado”
  • “order_id Y já teve ação Z executada”

O melhor lugar para isso quase sempre é o banco, porque é fonte de verdade.


3) Garanta unicidade no banco (constraints salvam sistemas)

Se duplicidade causa duplicação de registro, não confie só em lógica de aplicação. Use o banco como proteção.

Exemplos:

  • índice unique em invoice(event_id)
  • unique em notifications(message_id, channel)
  • unique em syncs(external_id)

A aplicação tenta criar; se já existe, você trata e segue.

Isso é robusto porque:

  • funciona mesmo com múltiplos workers
  • não depende de timing perfeito
  • reduz risco de corrida

4) Locks distribuídos (Redis) para evitar concorrência

Locks são úteis quando você quer garantir que apenas um worker execute determinada seção crítica ao mesmo tempo.

Exemplo:

  • processar um mesmo order_id
  • consolidar um relatório
  • importar lote único

Em Laravel, dá pra fazer lock via cache (Redis):

  • lock por chave: lock:order:123
  • se não adquirir, outro worker já está executando

Importante: lock não substitui idempotência. Ele reduz concorrência, mas não garante que um retry nunca vai rodar depois.


5) Use “unique jobs” do Laravel (quando couber)

Laravel tem suporte para jobs únicos (dependendo da versão/config), mas isso é mais útil para evitar enfileirar duplicado, não para evitar execução duplicada em qualquer cenário.

Use se:

  • você quer impedir spam de job igual
  • o job é claramente único por chave
  • você entende as limitações (especialmente com retries e falhas)

Mesmo com unique job, eu continuo recomendando idempotência + banco.


6) Controle retries, timeout e backoff com critério

Muita duplicidade aparece porque:

  • job estoura timeout → worker mata → tenta de novo
  • job demora demais → você acha que falhou → reprocessa manualmente
  • dependência externa oscila → retries “na pancada”

Ajuste bem:

  • timeout realista (nem baixo demais, nem infinito)
  • tries coerente com o impacto
  • backoff crescente para não sobrecarregar dependência externa

O objetivo é evitar “tempestade de retries”.


7) Separe “efeito colateral” do “estado principal”

Quando duplicidade é perigosa, normalmente é porque o job faz um efeito colateral irreversível (ex: cobrar cartão, enviar WhatsApp, emitir nota). A abordagem mais segura é:

  1. persistir um estado interno (“pendente”, “processando”, “concluído”)
  2. só então executar o efeito colateral
  3. registrar resultado e contexto

Isso cria trilha de auditoria e evita “executar no escuro”.


8) Instrumente: trace por job e correlação

Você só descobre duplicidade tarde se não tiver rastreabilidade.

Boas práticas:

  • job_id/correlation_id em logs
  • logar início/fim do job com chave do evento
  • métrica de “job duplicado evitado” (sim, isso ajuda muito)

Quando dá problema, você quer saber: “por que rodou duas vezes?” em 2 minutos, não em 2 horas.


Um padrão simples que funciona muito bem

Se eu tivesse que resumir num padrão prático:

  • chave idempotente (event_id)
  • tabela de processamento (processed_events) com unique
  • lock Redis opcional em trechos críticos
  • constraints no banco para proteger criação duplicada
  • logs com correlação

Isso cobre 95% dos casos reais.


Em produção, duplicidade em job não é exceção. É comportamento esperado do mundo real (retries, falhas, concorrência). O caminho profissional é aceitar isso e desenhar o job para ser seguro.

Job bom é o que pode rodar duas vezes sem te acordar de madrugada.

Leonardo

Engenheiro de Software especializado em PHP e Laravel, com ampla experiência no desenvolvimento de APIs, automações, sistemas de mensageria, estratégias de cache e integrações com serviços externos. Atua na arquitetura e evolução de sistemas escaláveis, com foco em performance, segurança, estabilidade e manutenibilidade do código, aplicando boas práticas de engenharia de software em ambientes de produção críticos.

Recent Posts

Sistema completo de cobranças via WhatsApp: boleto, Pix e NF-e na prática

Automatizar cobranças nunca foi simples. Entre regras bancárias, vencimentos, Pix, boletos registrados, notificações, inadimplência e…

52 minutos ago

Como monitorar aplicação e servidor pelo WhatsApp (logs, erros e alertas)

WhatsApp é um canal excelente para alerta porque ele tem uma característica que e-mail e…

21 horas ago

Arquitetura de uma API REST em Laravel preparada para produção

Em processos seletivos técnicos, não basta entregar código funcional. Cada vez mais, empresas avaliam arquitetura,…

2 dias ago

Automação de WhatsApp para WordPress: uma solução escalável para empresas e portais

O Notifish é um plugin para WordPress oficialmente aprovado no repositório do WordPress que permite…

3 dias ago

PHP além do CRUD: como escrever código que não vira problema em produção

A maioria dos desenvolvedores PHP sabe fazer CRUD.Isso não te torna pleno. Muito menos sênior.…

4 dias ago

Como identificar um projeto WordPress mal feito em 10 minutos

Você não precisa ser especialista nem passar horas auditando código para saber se um projeto…

5 dias ago