Integração com ERP legado tem um tipo de falha que eu odeio: o timeout. Não é um “não”. Também não é um “sim”. É o webservice SOAP que ficou calado no meio do caminho, e você fica sem saber se o Protheus gravou o pedido de venda ou se a requisição morreu antes de chegar na transação.

A reação automática, minha inclusive, é colocar retry. Erro transitório, tenta de novo, o job fica verde. Até o dia em que o financeiro pergunta por que a mesma peça saiu em dois pedidos.

O que o timeout esconde

Quando a gente chama um webservice de inclusão e toma timeout, existem pelo menos três mundos possíveis:

Do lado do cliente, os três parecem a mesma exceção. Timeout, ConnectionError, envelope SOAP pela metade. O log do job não distingue “não chegou” de “chegou e eu não ouvi a resposta”.

Retry sem memória é otimismo

Retry faz sentido para erro de rede, instabilidade curta, aquele webservice que cospe 500 uma vez e na segunda vai. Eu uso. Em lote de pedido de venda, com classificação fiscal no meio, eu só uso se a operação tiver uma identidade que o ERP (ou eu) consiga reconhecer na segunda tentativa.

Sem isso, o job “se recupera” e o negócio fica sujo. Dois pedidos, duas classificações, risco de NF duplicada no fluxo seguinte. O pior: o monitoramento fica feliz. Sucesso HTTP. Fila vazia. Quem reclama é gente, dias depois.

A regra que eu carrego agora

Se a operação cria alguma coisa no ERP, timeout não é “falhou”. É “não sei”. E “não sei” não se resolve com a mesma chamada crua de novo.

O que eu passei a gravar

Antes de falar com o SOAP, eu gero uma chave de idempotência do lado de cá: um id estável do pedido de origem (sistema de manutenção, item, operação). Essa chave vai junto no payload quando o webservice aceita um campo nosso, ou fica numa tabela de controle se o legado não tem onde guardar.

Na segunda tentativa o fluxo é outro:

  1. Olho se essa chave já tem um número de pedido no Protheus.
  2. Se tem, não incluo de novo. Devolvo o que já existe e sigo a vida.
  3. Se não tem, aí sim chamo a inclusão. Com lock distribuído na chave, para dois workers não dispararem o mesmo insert no mesmo segundo.

O lock não é firula. Sem ele, dois retries paralelos passam os dois na consulta “ainda não existe” e o ERP ganha dois inserts. Idempotência sem exclusão mútua é corrida. Eu já vi.

Retry do que é transitório. Não do que é negócio

Eu ainda reprocesso timeout, reset de conexão, 503. Não reprocesso validação fiscal, cliente bloqueado, item sem estoque. Isso não é intermitência, é o ERP falando não. Empurrar de novo só enche log e, em alguns webservices, ainda cria rascunho torto.

Outra coisa chata: o SOAP legado costuma ser serial. Um usuário, uma fila. Retry agressivo em paralelo, além de duplicar, derruba o próprio canal. Aqui o retry é curto, com espera, e um de cada vez por chave.

O que ficou

Retry é ferramenta boa. Sem chave e sem lock, é um jeito elegante de mentir para o dashboard. O job ficou verde. O pedido ficou duas vezes.

Hoje, quando alguém pede “só coloca um retry aí”, eu pergunto primeiro: se essa chamada passar duas vezes, o ERP cria duas coisas? Se a resposta for sim, a conversa muda de biblioteca de retry para desenho de identidade. O resto é detalhe de implementação.