Retries e idempotência
Aprenda a implementar retries com segurança, tratar timeouts e evitar operações duplicadas utilizando identificação, validação e controle de concorrência.
Falhas temporárias fazem parte de qualquer integração. Timeouts, instabilidades de rede e respostas inconclusivas podem acontecer mesmo quando a operação foi processada corretamente.
O risco aparece quando a aplicação repete uma operação sem saber se a tentativa anterior já produziu efeito. Em fluxos financeiros, retry sem controle pode gerar duplicidades e inconsistências.
Ao concluir esta página, você entenderá quando repetir uma operação, como diferenciar falhas temporárias de definitivas e como reduzir o risco de duplicidade utilizando identificação, validação e controle de concorrência.
Quando utilizar
Aplique essas práticas quando sua integração precisar:
- repetir chamadas após timeout ou instabilidade;
- recuperar operações com resultado inconclusivo;
- executar retries automáticos;
- evitar criação duplicada de entidades;
- processar operações em filas ou workers;
- garantir que uma mesma intenção de negócio não seja executada mais de uma vez.
Antes de começar
Antes de implementar retries:
- defina quais erros podem justificar uma nova tentativa;
- atribua um identificador interno único para cada operação;
- relacione esse identificador ao ID retornado pelo Asaas;
- utilize
externalReferencequando o recurso utilizado disponibilizar esse campo e ele for adequado ao fluxo; - defina como sua aplicação verificará se uma tentativa anterior já produziu efeito;
- implemente controle para impedir execuções concorrentes da mesma operação.
Como funciona
Uma falha de comunicação não significa automaticamente que a operação falhou.
Antes de repetir uma chamada, sua aplicação deve primeiro determinar se a tentativa anterior pode ter sido processada.
%%{init: {"flowchart": {"nodeSpacing": 28,"rankSpacing": 32,"diagramPadding": 8,"padding": 10}}}%%
flowchart TD
A["Executar operação"] --> B{"Resposta conclusiva?"}
B --> BSim(("Sim"))
B --> BNao(("Não"))
BSim --> C["Registrar resultado"]
BNao --> D["Registrar tentativa inconclusiva"]
D --> E{"Operação já existe?"}
E --> ESim(("Sim"))
E --> ENao(("Não"))
ESim --> F["Utilizar operação existente"]
ENao --> G{"Erro permite nova tentativa?"}
G --> GSim(("Sim"))
G --> GNao(("Não"))
GSim --> H["Aguardar backoff"]
H --> I["Executar nova tentativa"]
I --> B
GNao --> J["Registrar falha definitiva"]
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px,font-size:17px
classDef processo fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px,font-size:17px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:2px,font-size:17px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px,font-size:17px
classDef recuperacao fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:2px,font-size:17px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
class A inicio
class B,E,G decisao
class C,F sucesso
class D,H,I processo
class J recuperacao
class BSim,ESim,GSim respostaSim
class BNao,ENao,GNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
O retry deve ser a última etapa da decisão, não a primeira. Antes de executar uma nova tentativa, sua aplicação precisa avaliar o resultado anterior e confirmar se repetir a operação é realmente necessário.
1. Não trate timeout como falha confirmada
Quando uma chamada expira ou a conexão é interrompida, sua aplicação sabe apenas que não recebeu uma resposta conclusiva.
Isso não significa necessariamente que a operação deixou de ser processada.
Uma cobrança, transferência, assinatura ou outra entidade pode ter sido criada no Asaas mesmo que a resposta não tenha chegado até sua aplicação.
Por isso, o fluxo não deve ser:
timeout → repetir imediatamente
O fluxo deve considerar:
timeout → verificar resultado anterior → decidir se é necessário repetir
Não assuma que uma operação falhou apenas porque sua aplicação não recebeu a resposta. Repetir uma criação sem verificar o resultado anterior pode gerar uma nova entidade para a mesma intenção de negócio.
2. Diferencie falhas temporárias de falhas definitivas
Nem todo erro deve gerar retry.
Antes de repetir uma chamada, classifique o tipo de falha ocorrido.
| Situação | Tratamento |
|---|---|
| Timeout ou falha de conexão | Considere o resultado inconclusivo e verifique se a operação já foi executada antes de repetir |
| Erro temporário do servidor | Pode justificar nova tentativa depois de validação e espera adequada |
| Limite temporário de requisições | Aguarde antes de tentar novamente e respeite os limites aplicáveis |
| Erro de validação | Corrija os dados antes de enviar uma nova requisição |
| Regra de negócio rejeitada | Avalie a causa antes de decidir por uma nova tentativa |
| Erro de autenticação ou autorização | Corrija a configuração ou credencial antes de repetir |
Repetir a mesma requisição sem alterar a causa de uma falha definitiva apenas produz o mesmo erro novamente.
3. Identifique cada operação de forma única
Sua aplicação deve conseguir reconhecer a intenção de negócio que originou uma chamada.
Crie um identificador interno único antes da primeira tentativa e mantenha esse identificador durante todo o ciclo de retries.
Esse vínculo permite responder perguntas como:
- essa operação já foi enviada?
- existe uma tentativa em andamento?
- o Asaas já criou a entidade correspondente?
- qual ID do Asaas está relacionado a essa operação?
- quantas tentativas já ocorreram?
- qual foi o resultado da última tentativa?
O identificador deve existir antes da chamada, e não apenas depois de uma resposta bem-sucedida.
4. Utilize externalReference quando aplicável
externalReference quando aplicávelQuando o recurso utilizado disponibilizar externalReference, o campo pode ajudar a relacionar o registro criado no Asaas à operação existente no seu sistema.
Por exemplo:
{
"customer": "cus_000000000000",
"billingType": "PIX",
"value": 100,
"dueDate": "2026-09-30",
"externalReference": "pedido-98765"
}O valor utilizado deve ser estável para a mesma operação.
Evite gerar um novo externalReference a cada retry, pois isso elimina justamente a relação necessária para reconhecer diferentes tentativas da mesma intenção.
Gere o identificador da operação antes da primeira chamada e reutilize-o em todas as tentativas relacionadas à mesma intenção de negócio.
5. Relacione o identificador interno ao ID do Asaas
Quando uma chamada retornar com sucesso, armazene a relação entre:
- identificador interno da operação;
externalReference, quando utilizado;- ID retornado pelo Asaas;
- resultado da tentativa;
- data e horário;
- estado conhecido naquele momento.
Essa relação deve ser mantida mesmo depois da conclusão da operação.
Ela será útil para:
- consultas posteriores;
- processamento de Webhooks;
- reconciliação;
- investigação de falhas;
- prevenção de novas tentativas indevidas.
6. Verifique o resultado antes de repetir
Quando uma tentativa tiver resultado inconclusivo, procure determinar se a operação anterior já produziu efeito.
O fluxo recomendado é:
%%{init: {"flowchart": {"nodeSpacing": 28,"rankSpacing": 32,"diagramPadding": 8,"padding": 10}}}%%
flowchart TD
A["Tentativa com resultado inconclusivo"] --> B["Recuperar identificador da operação"]
B --> C["Verificar registros locais"]
C --> D{"Existe ID do Asaas associado?"}
D --> DSim(("Sim"))
D --> DNao(("Não"))
DSim --> E["Consultar ou utilizar operação existente"]
DNao --> F["Verificar se a operação foi criada"]
F --> G{"Operação encontrada?"}
G --> GSim(("Sim"))
G --> GNao(("Não"))
GSim --> H["Associar ID encontrado"]
H --> E
GNao --> I["Avaliar nova tentativa"]
classDef inicio fill:#DBEAFE,stroke:#2563EB,color:#1E3A8A,stroke-width:3px,font-size:17px
classDef processo fill:#E0F2FE,stroke:#0284C7,color:#0C4A6E,stroke-width:2px,font-size:17px
classDef decisao fill:#FEF3C7,stroke:#D97706,color:#78350F,stroke-width:2px,font-size:17px
classDef sucesso fill:#DCFCE7,stroke:#16A34A,color:#14532D,stroke-width:3px,font-size:17px
classDef recuperacao fill:#FEE2E2,stroke:#DC2626,color:#7F1D1D,stroke-width:2px,font-size:17px
classDef respostaSim fill:#22C55E,stroke:#15803D,color:#FFFFFF,stroke-width:3px
classDef respostaNao fill:#EF4444,stroke:#B91C1C,color:#FFFFFF,stroke-width:3px
class A inicio
class B,C,F processo
class D,G decisao
class E,H sucesso
class I recuperacao
class DSim,GSim respostaSim
class DNao,GNao respostaNao
linkStyle default stroke:#94A3B8,stroke-width:2px
Se a operação já existir, utilize o registro encontrado em vez de criar um novo.
Somente prossiga com uma nova tentativa quando houver elementos suficientes para concluir que a operação anterior não produziu o efeito esperado.
7. Controle retries concorrentes
Mesmo utilizando um identificador único, sua aplicação ainda pode gerar duplicidades se vários processos executarem a mesma operação simultaneamente.
Isso pode acontecer, por exemplo, quando:
- dois workers recebem a mesma tarefa;
- uma mensagem é entregue mais de uma vez por uma fila;
- o usuário envia a mesma ação repetidamente;
- dois servidores processam a mesma operação;
- um retry começa enquanto a tentativa anterior ainda está em andamento.
Nesse cenário, dois processos podem verificar quase ao mesmo tempo que a operação ainda não existe e ambos executar a criação.
Implemente algum mecanismo que garanta que apenas um processo avance com a mesma operação por vez.
Dependendo da arquitetura, isso pode ser feito com:
- lock distribuído;
- controle transacional;
- restrição única no banco de dados;
- estado interno de processamento;
- serialização por chave de negócio.
O mecanismo escolhido depende da infraestrutura da sua aplicação. O requisito é impedir que duas execuções concorrentes realizem o mesmo efeito.
8. Aplique espera progressiva entre tentativas
Retries imediatos em sequência aumentam a carga sobre a integração e podem repetir chamadas enquanto a causa da falha ainda está presente.
Utilize uma estratégia de backoff, aumentando o intervalo entre as tentativas.
Por exemplo:
1ª nova tentativa: aguardar 1 segundo
2ª nova tentativa: aguardar 2 segundos
3ª nova tentativa: aguardar 4 segundos
4ª nova tentativa: aguardar 8 segundosOs valores devem ser ajustados ao comportamento da operação e aos limites aplicáveis à API.
Também estabeleça um número máximo de tentativas. Uma operação não deve permanecer em retry indefinidamente.
9. Registre todas as tentativas
Cada tentativa deve deixar informações suficientes para reconstruir o que aconteceu.
Registre, quando aplicável:
- identificador interno da operação;
- ID do Asaas, quando disponível;
- número da tentativa;
- data e horário;
- resultado HTTP;
- classificação da falha;
- decisão tomada após o erro;
- intervalo aplicado antes da próxima tentativa;
- estado final do processamento.
Esses dados permitem diferenciar uma instabilidade isolada de um problema recorrente na integração.
Atenção — duplicidade e erros comuns
Evite implementações que:
- tratam timeout como confirmação de que a operação não ocorreu;
- repetem uma criação imediatamente após perder a resposta;
- executam retry para qualquer tipo de erro;
- repetem falhas de validação sem corrigir o payload;
- não possuem um identificador interno por operação;
- geram um novo identificador a cada tentativa;
- não relacionam o registro local ao ID do Asaas;
- procuram operações apenas por combinações frágeis como valor, data e cliente;
- permitem que múltiplos processos repitam a mesma operação simultaneamente;
- executam tentativas em sequência sem intervalo;
- realizam retries indefinidamente.
Retry não significa repetir a chamada automaticamente. Significa recuperar uma operação com segurança depois de determinar o que aconteceu na tentativa anterior.
Confirme sua arquitetura
Antes do go-live, confirme se sua aplicação consegue responder:
- Quais erros podem gerar uma nova tentativa?
- Quais erros exigem correção antes de qualquer retry?
- O que acontece quando uma chamada termina em timeout?
- Existe um identificador único criado antes da primeira tentativa?
- Esse identificador permanece igual durante os retries?
- O ID retornado pelo Asaas é associado à operação interna?
- É possível verificar se a operação anterior já produziu efeito?
- O sistema evita duas execuções simultâneas da mesma operação?
- Existe espera progressiva entre tentativas?
- Existe um limite máximo de retries?
- Todas as tentativas ficam registradas para diagnóstico?
Se essas condições não estiverem atendidas, uma tentativa criada para recuperar uma falha pode gerar um problema adicional: executar novamente uma operação que já havia sido concluída.
Boas práticas
- considere timeout como resultado inconclusivo, e não como falha confirmada;
- classifique o erro antes de decidir por um retry;
- crie o identificador interno antes da primeira tentativa;
- utilize
externalReferencequando o recurso disponibilizar esse campo e ele fizer sentido para o fluxo; - mantenha o mesmo identificador durante todas as tentativas da operação;
- armazene o ID retornado pelo Asaas assim que ele estiver disponível;
- verifique o resultado anterior antes de criar uma nova operação;
- proteja o fluxo contra execuções concorrentes;
- utilize backoff entre tentativas;
- estabeleça limite máximo de retries;
- mantenha histórico suficiente para diagnosticar falhas e duplicidades.
Próximos passos
Depois de estruturar retries e mecanismos para evitar duplicidades, valide se todos os componentes da integração estão preparados para operar no ambiente produtivo:
Updated about 2 hours ago
