Arquitetura · Integrações · Critérios de aceite

Idempotência em integrações ERP: repetir a mensagem sem repetir a operação

O consumidor salvou o envio de um pedido. Antes de confirmar a mensagem ao transporte, o processo caiu. Na nova tentativa, o mesmo evento chegou outra vez. O sistema precisa reconhecer o resultado já confirmado.

O problema começa depois do caminho feliz

Em uma integração entre ERP e expedição, uma mensagem repetida pode gerar uma segunda ordem, repetir uma reserva ou produzir uma divergência operacional. Antes de escolher uma ferramenta, defina o efeito que deve acontecer uma única vez e o identificador que permite reconhecer sua repetição.

Este projeto usa três bancos SQLite separados: ERP fictício, transporte local e consumidor. Ele demonstra uma decisão de arquitetura e seus testes. Não acessa SAP, SQS, sistemas de clientes ou dados de produção.

Explore o cenário

Duas tentativas. Um efeito de envio.

Simulação visual, sem servidor ou banco real. Clique em sequência para observar a decisão; os testes Python abaixo são a evidência executável.

  1. Gravar o envio, mas simular falha antes do ACK.
  2. Reentregar o mesmo evento.
  3. Cancelar e receber uma atualização antiga.
Tentativas do evento de envio0
Efeitos locais de envio0
Estado do pedidoCREATED · v1

Pronto: pedido fictício criado, versão 1.

A decisão: confirmar o efeito e a deduplicação juntos

O consumidor usa a chave (consumer, event_id). O mesmo ID com conteúdo diferente é um conflito; não pode desaparecer silenciosamente como se fosse uma repetição normal. Por isso, o laboratório também compara um fingerprint do payload.

  1. Abrir uma transação local e verificar a identidade do evento.
  2. Validar a versão do pedido e as regras de estado.
  3. Gravar estado, efeito local e resultado de processamento na mesma transação.
  4. Confirmar a mensagem ao transporte somente depois do commit.

Falha antes do commit reverte tudo. Falha depois do commit e antes do ACK deixa o resultado persistido: a nova tentativa encontra a inbox e retorna duplicate, sem repetir o efeito. O teste de reinício usa um processo Python separado, não apenas um conjunto em memória.

Outbox, transporte e consumidorERP grava pedido e outbox na mesma transação. Relay pode repetir a entrega. Consumidor grava estado, inbox e efeito em uma transação local, e então confirma ao transporte.ERP fictícioPedido + outboxUma transação localTransporte localEntrega pode repetirConsumidorEstado + inbox + efeitoUma transação localACK somente após commit
Não há uma transação única envolvendo os três bancos.

Por que existe uma outbox na origem?

O ERP fictício grava a mudança do pedido e a intenção de publicar o evento juntos. O relay entrega ao transporte e depois marca a outbox. Se cair entre esses passos, pode entregar novamente. A outbox trata a janela de perda na origem; a idempotência continua necessária no consumidor.

E as mensagens fora de ordem?

Neste cenário, uma versão antiga é registrada como stale, sem regredir o pedido. Uma versão futura com lacuna exige recuperar a dependência e tentar novamente. Cancelamento é terminal. Essas políticas são explícitas e testadas, mas devem ser definidas com o negócio em cada integração.

O que foi executado

14 testes automatizados passaram no ambiente de desenvolvimento. O resultado não mede desempenho, disponibilidade nem economia em clientes. A revisão externa permanece pendente.

CenárioEvidência observada
16 entregas concorrentes do mesmo evento1 aplicação e 15 duplicatas; um efeito local
Falha antes do commitEstado, efeito e inbox revertidos; nova tentativa pode aplicar
Commit seguido de falha no ACKOutro processo reconhece o evento persistido; não repete o efeito
Falha no relay após entregaTransporte recebe novamente; consumidor deduplica
Evento antigo após cancelamentoPedido permanece CANCELLED, versão 3
Erro persistente e replayHistórico preservado, causa corrigida e identidade original mantida

A demonstração termina com três efeitos de negócio locais: criação, envio e cancelamento. O envio aparece uma vez, apesar das duas tentativas de entrega. Confira o JSON gerado pela execução e os testes completos.

Reproduza sem conta paga

Use Python 3.10 ou superior. Não é necessário instalar pacotes externos. Na pasta do projeto:

python -m unittest discover -s tests -v
python lab.py demo --output evidence/minha-execucao.json

Para inspecionar os bancos, use python lab.py demo --directory .runtime. O README explica a limpeza restrita dos arquivos gerados e os resultados esperados. O exemplo usa somente dados inventados.

Onde esta demonstração termina

O papel da liderança técnica nessa conversa

A decisão precisa ser compreendida por quem desenvolve, testa e opera. O Tech Lead explicita o efeito protegido, a janela de falha e o limite da evidência; gestão do projeto coordena dependências; operação e responsáveis de negócio definem o aceite. Um teste de caminho feliz não encerra essa discussão.

Continue a leitura

Referências técnicas

Laboratório autoral desenvolvido com assistência de IA e testes automatizados. Exemplos fictícios; não representa AtisWork, CPFL Energia ou clientes. Última revisão: 9 de novembro de 2026.