Webhook duplicado processado sem idempotência
Esse erro ocorre quando a integração recebe o mesmo webhook mais de uma vez e executa novamente a regra de negócio sem verificar se o evento já foi processado.
O recebimento repetido de um evento não significa que a ação deve ser executada novamente. A integração precisa reconhecer duplicidades e responder com sucesso sem repetir seus efeitos.
Diferentemente do erro Webhook recebido, mas não persistido, neste caso o problema está na ausência de controle sobre eventos já registrados ou processados.
Como identificar
- o mesmo evento aparece mais de uma vez nos logs;
- a mesma ação é executada repetidamente para uma única operação;
- notificações, liberações ou atualizações são duplicadas;
- existem múltiplos processamentos com o mesmo identificador de evento;
- o sistema não verifica se o evento já foi recebido;
- não existe status interno para diferenciar eventos recebidos e processados;
- dois processos podem executar o mesmo evento simultaneamente;
- o problema ocorre após uma nova tentativa de entrega do webhook.
Como corrigir
- Identifique os eventos que foram processados mais de uma vez.
- Confirme quais ações foram duplicadas.
- Corrija os efeitos indevidos, quando aplicável.
- Persista o identificador do evento antes de iniciar o processamento.
- Utilize uma chave única para controlar eventos já recebidos.
- Consulte essa chave antes de executar a regra de negócio.
- Quando o evento já estiver processado, não execute a ação novamente.
- Quando o processamento anterior estiver pendente ou com erro, retome-o de forma segura.
- Impeça que processos concorrentes executem o mesmo evento.
- Registre o resultado de cada processamento.
Fluxo recomendado: receber → identificar o evento → consultar o registro → persistir se for novo → processar uma única vez → atualizar o status → responder.
Fluxo de diagnóstico
1. Identificação e tratamento da duplicidade
%%{init: {"flowchart": {"nodeSpacing": 18,"rankSpacing": 24,"diagramPadding": 4,"padding": 7
}}}%%
flowchart TD
A["Webhook recebido<br/>pelo endpoint"] --> B{"Existe registro com o mesmo<br/>identificador do evento?"}
B --> BSim(("Sim"))
B --> BNao(("Não"))
BSim --> C{"O evento já foi<br/>processado?"}
BNao --> D["Persistir o evento<br/>com status recebido"]
C --> CSim(("Sim"))
C --> CNao(("Não"))
CSim --> E["Não executar novamente<br/>a regra de negócio"]
CNao --> F["Continuar o processamento<br/>pendente"]
D --> G["Processar o evento<br/>uma única vez"]
F --> G
E --> H["Registrar a entrega<br/>duplicada"]
G --> I["Atualizar o status<br/>para processado"]
H --> J["Responder sucesso sem<br/>repetir a ação"]
I --> J
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:3px
classDef correcao fill:#FFEDD5,stroke:#EA580C,color:#7C2D12,stroke-width:2px
classDef validacao fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px
classDef analise fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:3px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
classDef respostaDuvida fill:#8B5CF6,stroke:#6D28D9,color:#FFFFFF,stroke-width:3px
class A inicio
class B,C decisao
class D,F,G,I correcao
class H validacao
class J sucesso
class E analise
class BSim,CSim respostaSim
class BNao,CNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
linkStyle 1,5 stroke:#22C55E,stroke-width:4px
linkStyle 2,6 stroke:#EF4444,stroke-width:4px
2. Processamento com controle de idempotência
%%{init: {"flowchart": {"nodeSpacing": 18,"rankSpacing": 24,"diagramPadding": 4,"padding": 7
}}}%%
flowchart TD
A["Antes de processar<br/>o webhook"] --> B{"Existe uma chave única<br/>para o evento?"}
B --> BSim(("Sim"))
B --> BNao(("Não"))
BNao --> C["Definir uma chave<br/>idempotente"]
BSim --> D["Consultar o armazenamento<br/>de eventos"]
C --> D
D --> E{"A chave já está<br/>registrada?"}
E --> ESim(("Sim"))
E --> ENao(("Não"))
ESim --> F{"O status é<br/>processado?"}
ENao --> G["Registrar o evento<br/>com status recebido"]
F --> FSim(("Sim"))
F --> FNao(("Não"))
FSim --> H["Responder sucesso sem<br/>repetir o processamento"]
FNao --> I["Bloquear a execução<br/>concorrente"]
G --> I
I --> J["Executar a regra de negócio<br/>uma única vez"]
J --> K{"O processamento<br/>foi concluído?"}
K --> KSim(("Sim"))
K --> KNao(("Não"))
KSim --> L["Atualizar o status<br/>para processado"]
KNao --> M["Registrar o erro e manter<br/>para reprocessamento"]
L --> N["Responder sucesso"]
H --> N
M --> O["Reprocessar utilizando<br/>a mesma chave"]
O --> I
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:3px
classDef correcao fill:#FFEDD5,stroke:#EA580C,color:#7C2D12,stroke-width:2px
classDef validacao fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px
classDef analise fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:3px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
classDef respostaDuvida fill:#8B5CF6,stroke:#6D28D9,color:#FFFFFF,stroke-width:3px
class A inicio
class B,E,F,K decisao
class C,G,I,J,L,O correcao
class D validacao
class N sucesso
class H,M analise
class BSim,ESim,FSim,KSim respostaSim
class BNao,ENao,FNao,KNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
linkStyle 1,7,11,18 stroke:#22C55E,stroke-width:4px
linkStyle 2,8,12,19 stroke:#EF4444,stroke-width:4px
O primeiro fluxo orienta como identificar e tratar um evento recebido novamente, enquanto o segundo mostra como impedir que a regra de negócio seja executada mais de uma vez.
Como prevenir
Persista todos os eventos recebidos e utilize uma chave única para controlar o processamento. Mantenha status internos, como recebido, processado e erro, e consulte esse registro antes de executar a regra de negócio.
Utilize restrições de unicidade, controle de concorrência e operações idempotentes. Teste o fluxo enviando o mesmo evento mais de uma vez e confirme que seus efeitos ocorrem somente uma vez.
O mesmo webhook pode ser recebido novamente. A regra de negócio deve ser executada apenas uma vez.
Updated about 12 hours ago
