Zopio

Quando é perigoso tentar um pagamento novamente após um timeout?

Retries se tornam perigosos quando uma falha de transporte é tratada como falha de negócio. Se o provedor concluiu uma authorization ou capture mas a resposta não chegou ao seu sistema, um retry cego pode criar uma segunda ação financeira. O correto é preservar a incerteza, recuperar o estado e repetir somente com garantias explícitas de idempotência.

01

O timeout só descreve o que o cliente sabe

Um timeout de rede significa que o caller não recebeu uma resposta conclusiva no prazo. Não prova que o sistema remoto rejeitou, reverteu ou nunca recebeu a solicitação. Em payments, authorization, capture ou refund podem ter produzido efeito financeiro mesmo quando o cliente recebeu uma exceção.

Após um timeout ambíguo, o estado seguro não é failed, mas unknown. Transformar unknown em failed mistura duas realidades diferentes e aumenta o risco de execução duplicada.

02

Idempotência muda a decisão de retry

O retry é mais seguro quando o provedor suporta idempotência naquela operação e a mesma key original pode ser reutilizada. A identidade deve representar a ação de negócio, não o attempt HTTP. Gerar uma key nova em cada retry permite que o provedor trate cada chamada como uma nova ação.

Operações suportadas, retenção de keys, concorrência e retorno de uma chamada repetida variam entre provedores. Essas diferenças devem fazer parte da lógica de payment recovery.

03

Recupere o estado antes de criar uma segunda ação financeira

Quando o resultado é incerto, primeiro reconcilie a intenção com o estado do provedor: consulte por merchant reference, consuma eventos ou use um mapping durável entre attempt e recurso do provedor. Só depois considere nova execução.

Por isso payment retry é uma decisão de orchestration, não apenas de HTTP reliability.

04

Regra prática

Tente novamente automaticamente apenas quando a operação for segura sob o contrato de idempotência do provedor ou quando o sistema tiver confirmado que a ação original não foi concluída. Caso contrário, mova o pagamento para um recovery state explícito.

05

Separe falha de transporte de falha de estado de negócio

Um payment state machine confiável precisa separar pelo menos três conceitos: o estado da requisição do cliente, o estado da operação no provedor e o business state que seu sistema decide expor. No happy path esses estados costumam coincidir, por isso é tentador colapsá-los. O risco aparece quando a rede falha: uma requisição pode falhar localmente enquanto a operação remota conclui com sucesso, ou o provedor pode aceitar o trabalho e publicar o resultado de forma assíncrona depois que a chamada original já expirou.

A consequência prática é que um transport error não deve disparar automaticamente transições de negócio irreversíveis. Um payment attempt que termina em timeout pode precisar de um estado como pending verification, unknown ou recovery required. Esse estado permite interromper a progressão automática enquanto o sistema reúne evidências e evita que serviços downstream interpretem ausência de resposta como prova de que nenhum dinheiro se moveu.

06

Construa uma hierarquia de recovery consciente do provedor

Recovery deve começar pela fonte de verdade mais forte disponível. Se o provedor permite lookup por idempotency key, merchant reference, payment intent ou provider transaction ID, use isso antes de criar um novo attempt. Se um evento durable do provedor é esperado, correlacione-o com o attempt original e aguarde dentro de uma janela de recovery limitada. Se nenhum mecanismo existe, é melhor escalar para reconciliação atrasada ou manual do que adivinhar.

Esse recovery específico explica por que bibliotecas genéricas de HTTP retry não bastam em operações financeiras. Repetir um read é diferente de repetir uma authorization; authorization é diferente de capture; repetir um refund pode ser ainda mais perigoso porque a transação customer-facing talvez já esteja concluída. A policy de recovery deve viver perto da semântica de payments, não apenas da semântica de rede.

07

Desenhe observability ao redor da incerteza

Dashboards operacionais devem mostrar pagamentos incertos como um cohort próprio. Acompanhe quantos attempts entram em estado ambíguo, quais provedores os geram, quanto tempo o recovery leva e quantos casos são resolvidos por lookup, webhook, reconciliação ou intervenção manual. Se estados unknown ficam escondidos em um error rate genérico, o time otimiza a métrica errada e pode aumentar retries, justamente o comportamento que eleva risco de duplicidade.

Alertas também devem separar crescimento de outcomes ambíguos de crescimento de declines explícitos. Um provedor com mais issuer declines tem um problema diferente de outro que recebe a requisição e depois faz timeout. O primeiro afeta conversão; o segundo adiciona incerteza de conversão e risco de integridade financeira. Classes diferentes de falha precisam de playbooks diferentes.

08

Framework de decisão antes de um retry automático

Antes de repetir, responda quatro perguntas: sabemos que a operação original não concluiu? O provedor garante comportamento idempotente para essa operação e key? O attempt original pode ser consultado ou reconciliado? Qual o impacto financeiro se os dois attempts concluírem? Se as duas primeiras respostas são incertas e o impacto de duplicidade é material, o retry automático deve parar.

Esse modelo favorece deliberadamente correção financeira em vez de conclusão imediata. Isso não significa aceitar experiência ruim. Significa tornar recovery explícito: mostrar pending quando adequado, continuar verification de forma assíncrona e comunicar um status ao cliente somente quando houver evidência. Alguns segundos de incerteza honesta normalmente custam menos do que duplicate charge e o suporte, refund, dispute e perda de confiança que vêm depois.

Conclusões práticas

Timeout é resultado de transporte indeterminado, não prova de falha.

Use a mesma identidade de idempotência para a mesma ação.

Modele semânticas específicas de cada provedor.

Reconcilie estados unknown antes de reexecutar.

Referências principais