FT-MSG-IDEMPOTENCY· 1.0.0Integrações
Idempotency em mensagens EDI — Idempotency-Key + fingerprint
Como o Lefia detecta e bloqueia mensagens duplicadas at-insert via fingerprint SHA-256 + header Idempotency-Key (padrão Stripe). UNIQUE parciais por message_type, race fallback via 23505.
Atualizado em 8/6/2026
Idempotency em mensagens EDI
Atualizado 2026-05-06. Aplicado em/api/edi-hub/receive-messagee/api/webhook/[integrationId].
Por que existe
Source SAP retransmite SalesOrder/BillingDocument quando perde ack. Webhook externo manda evento 2x quando sua infra dá timeout. Sem idempotency, Lefia reprocessa o mesmo pedido N vezes — destino recebe duplicata, sistema externo sangra.
Solução padrão Stripe: chave de idempotência única por mensagem, bloqueia at-insert no banco.
2 modos de detecção
1. Header Idempotency-Key (recomendado pra clientes que controlam o source)
Cliente envia header HTTP:
POST /api/edi-hub/receive-message
Idempotency-Key: order-12345-attempt-2
Content-Type: application/json
{ ...payload... }
Lefia armazena a chave. Re-envio com mesma key → 200 OK com a resposta original (não cria nova mensagem).
2. Fingerprint SHA-256 (auto, pra qualquer source)
Quando não vem
Idempotency-Key, Lefia calcula fingerprint:SHA-256(message_type_id + concat(duplicate_key_fields))
duplicate_key_fields é configurado por message_type (ex: ["E1EDK01.BELNR", "E1EDK01.DOCDAT"] pra ORDERS05). Se já existe mensagem com mesmo fingerprint dentro da janela configurada → bloqueia at-insert.UNIQUE INDEX parcial
CREATE UNIQUE INDEX uq_messages_fingerprint
ON messages (tenant_id, environment_id, fingerprint)
WHERE fingerprint IS NOT NULL;
Race condition tratado: se 2 requests simultâneos passam pelo SELECT, INSERT, um vai pegar
23505 (unique violation) — fallback retorna a mensagem existente.Configuração
Em
message_types:
duplicate_key_fields(jsonb): paths usados no fingerprintduplicate_window_hours(int): janela em horas (ex: 24h)
Sem
duplicate_key_fields configurado, fallback é [docnum]. Sem duplicate_window_hours, default é 168h (7 dias).Como ver duplicatas detectadas
/admin/audit filtra por action = "message.duplicate_blocked". Cada bloqueio gera audit_event com fingerprint + reference original.Roadmap relacionado
- #60 Idempotency at-insert (delivered)
- Casos não cobertos hoje: payload semantically equivalent mas serialized diferente (ex: chave em ordem diferente). Próxima evolução é canonicalize antes de hash.
Histórico de versões
- 1.0.0
Idempotency at-insert pra mensagens EDI. Fingerprint SHA-256 (chave + payload) + Idempotency-Key header (Stripe pattern). UNIQUE parciais. Reaproveita duplicate_key_fields. Race fallback via 23505. Aplicado em /api/edi-hub/receive-message e /api/webhook/[integrationId].
5/6/2026 · new