Processamento Exatamente Uma Vez com Webhooks

Oi pessoal, estou lidando com um problema de confiabilidade mais avançado no n8n relacionado a workflows acionados por webhook.
Tenho um workflow:
Webhook → Processo → Banco de Dados
O serviço externo às vezes tenta novamente o mesmo evento de webhook (por exemplo, devido a timeouts), então o n8n recebe requisições duplicadas com o mesmo payload.
No momento, isso causa:
• Registros duplicados no banco de dados
• Ações duplicadas downstream (e-mails, chamadas de API, etc.)
Exemplo de payload:
{
“event_id”: “abc123”,
“user_id”: 42,
“action”: “created”
}
Se o mesmo event_id é enviado duas vezes, ele é processado duas vezes.
O que tentei
• Verificações básicas em um nó Function
• Upserts de banco de dados
• Adição de delays
Mas nenhuma dessas abordagens garante totalmente o processamento exatamente uma vez.
O desafio
Eu quero garantir:
• Cada evento é processado apenas uma vez
• Manipulação segura de retries
• Nenhum efeito colateral duplicado

Descreva o problema/erro/pergunta

Qual é a mensagem de erro (se houver)?

Por favor, compartilhe seu workflow

(Selecione os nós na sua tela e use os atalhos de teclado CMD+C/CTRL+C e CMD+V/CTRL+V para copiar e colar o workflow.)

Compartilhe o resultado retornado pelo último nó

Informações sobre sua configuração do n8n

  • Versão do n8n:
  • Banco de dados (padrão: SQLite):
  • Configuração n8n EXECUTIONS_PROCESS (padrão: own, main):
  • Executando n8n via (Docker, npm, n8n cloud, aplicativo desktop):
  • Sistema operacional:

Oi @Keira_Becky Você está lidando com um problema de idempotência, e a única solução confiável é rastrear eventos processados — não há “exatamente uma vez” integrado no n8n.

Use o event_id como uma chave única e deixe seu banco de dados aplicar isso.

Tente isto

  1. Armazene event_id no BD com restrição UNIQUE

CREATE TABLE events (
event_id TEXT PRIMARY KEY,
payload JSONB
);

  1. Insira antes de processar

INSERT INTO events (event_id, payload)
VALUES ({{$json.event_id}}, {{$json}})
ON CONFLICT (event_id) DO NOTHING;

Então se a inserção for bem-sucedida → processe o evento
Se houver conflito → pule (já foi processado)

Obrigado @Niffzy

Consegui resolver inserindo antes do processamento