Integração resiliente
Retry, backoff exponencial e jitter, com uma demo local
Como tentar de novo sem piorar a fila
Quando uma requisição é recusada ou demora demais, tentar de novo na hora costuma piorar a fila. O caminho que funciona é esperar um pouco mais a cada tentativa e espalhar essas esperas, para várias integrações não voltarem todas juntas.
Na Clicksign, passar do limite de requisições devolve 429 Too Many Requests. Os números de cada ambiente e os headers X-Rate-Limit, X-Rate-Limit-Remaining e X-Rate-Limit-Reset estão em Limite de requisições. Para acompanhar um documento ou uma jornada, use webhooks em vez de consultar em loop. O contraste entre polling e webhook está em Introdução a webhooks.
Glossário
| Termo | O que é |
|---|---|
| Timeout | Tempo máximo de espera de cada chamada. Passou o prazo, a integração desiste daquela tentativa. |
| Retry | Nova tentativa depois de uma falha que pode passar, como 429, 5xx, timeout ou queda de rede. |
| Backoff exponencial | Espera que dobra a cada tentativa, com um teto. Por exemplo, 1 s, 2 s e 4 s. |
| Jitter | Sorteio somado a essa espera, para várias integrações não voltarem no mesmo instante. |
| Limite de requisições | Quantidade de chamadas aceitas numa janela de tempo. Passou, a resposta é 429. |
| Idempotência | Repetir a operação sem criar um segundo recurso. Consulta pode ser repetida. Criação e alteração pedem conferir se o recurso já existe. |
| Polling | Consultar de novo, em intervalos, para saber se algo mudou. |
| Webhook | Aviso enviado pela Clicksign quando algo muda, no lugar dessa consulta. |
O que fazer na integração
- Defina um tempo máximo de espera em cada chamada. Sem esse prazo, uma resposta lenta fica ocupando a integração por tempo indefinido.
- Tente de novo em
429, em5xx, em timeout e em falha de rede. Um500pode ser uma instância momentaneamente ruim; a tentativa seguinte pode cair em outra. - Não tente de novo um erro de validação ou de autenticação (
400,401,403,404,422). A requisição está errada; repetir não muda o resultado. - Aumente a espera a cada tentativa e imponha um teto. É o backoff exponencial: 1 s, 2 s, 4 s, e por aí vai, até um máximo.
- Some um sorteio a essa espera. É o jitter. Sem ele, quem recebeu
429no mesmo instante volta a chamar junto, e a rajada só muda de lugar. - Se a resposta trouxer
X-Rate-Limit-Reset, espere pelo menos até esse horário antes da próxima tentativa. - Limite o número de tentativas. Uma queda longa não se resolve insistindo.
- Consulta pode ser repetida. Criação e alteração pedem cuidado: se o timeout chegou depois que a Clicksign já tinha gravado o recurso, uma nova tentativa pode criar outro. Confira se ele já existe antes de criar de novo.
Se várias tentativas seguidas falharem, pare e retome mais tarde com uma chamada só. Continuar no automático mantém a fila cheia. Em um lote, distribua os envios ao longo do tempo em vez de disparar tudo no mesmo instante.
Uma demo para ver a diferença
A demo roda no seu computador. O servidor dela falha de propósito. Não é a API da Clicksign, e os limites dela não são os da plataforma.
Dez clientes ligam para esse servidor ao mesmo tempo, como uma rotina agendada. Dá para trocar a estratégia e ver o que acontece com a taxa de sucesso e com a quantidade de ligações.
Legenda do mosaico: 200 atendeu, 429 recusou, timeout travou. Na demo, a recusa acontece quando chega mais de 1 requisição a cada 300 ms. O travamento acontece nos segundos terminados em 2, 3, 5 e 7.
A primeira vez leva aprox. 10 minutos.
Baixar a demo
Projeto completo em um zip (27 KB). Só precisa do Python 3.9 ou mais novo e do Chrome ou do Edge.
Ver o código
Servidor, clientes e laboratório no repositório público, para ler antes de baixar.
Windows
- Instale o Python. Entre em python.org/downloads e baixe o instalador. Na primeira tela, marque Add python.exe to PATH antes de clicar em Install Now.
- Extraia o zip. No Explorador de Arquivos, clique com o botão direito em
demo-retry.zipe escolha Extrair tudo…. A pastademo-retryprecisa conter o arquivoserver.py. - Abra o PowerShell nessa pasta. Clique na barra de endereço do Explorador, apague o caminho, digite
powershelle aperte Enter. - Ligue o servidor.
python --version
python server.pyA janela fica aberta e mostra cada ligação em verde, amarelo ou vermelho. O servidor confirma assim:
Servidor ouvindo em http://localhost:8013
Instabilidade: trava nos segundos terminados em 2, 3, 5 ou 7
Rate limit: 1 requisição a cada 300 ms- Abra o mosaico no Chrome ou no Edge:
http://localhost:8013/mosaico.html. Troque a estratégia nos botões do topo. Para desligar, volte ao PowerShell e aperte Ctrl + C.
macOS
- Instale o Python pelo arquivo
.pkgem python.org/downloads. - Dê dois cliques no zip. Arraste a pasta
demo-retrypara a Mesa. - No Terminal:
cd ~/Desktop/demo-retry
python3 --version
python3 server.py- Abra
http://localhost:8013/mosaico.htmlno Chrome ou no Edge. O Safari não abre os dez clientes. Deixe o terminal aberto: cada ligação aparece em verde, amarelo ou vermelho, com as mesmas três linhas de confirmação do Windows. Para desligar, Control + C.
Linux
python3 --version
cd ~ && unzip ~/Downloads/demo-retry.zip
cd ~/demo-retry && python3 server.pySe python3 não existir: sudo apt install python3 (Ubuntu/Debian) ou sudo dnf install python3 (Fedora). Abra http://localhost:8013/mosaico.html no Chrome ou no Chromium. Deixe o terminal aberto: cada ligação aparece em verde, amarelo ou vermelho, com as mesmas três linhas de confirmação do Windows.
Se algo der errado
- "python não é reconhecido como nome de cmdlet" (Windows). O instalador rodou sem Add python.exe to PATH. Tente
py server.py. Se não funcionar, rode o instalador de novo, escolha Modify e marque Add Python to environment variables. Feche e abra o PowerShell. - Digitei
pythone abriu a Microsoft Store (Windows). Usepy server.py, ou desligue os aliasespythonem Configurações → Aplicativos → Configurações avançadas de aplicativos → Aliases de execução de aplicativo. - "command not found: python" (macOS). O comando é
python3. - "No such file or directory: server.py". O terminal está em outra pasta. Às vezes o zip cria
demo-retry/demo-retry. Entre até ver oserver.py. No Windows, se a Área de Trabalho estiver no OneDrive, o caminho éOneDrive\Área de Trabalho. - "Address already in use" ou "Só é permitido um uso de cada endereço". Já existe um servidor nessa porta. Feche a outra janela com Ctrl + C e tente de novo.
- O mosaico abre e os quadros ficam em branco. Cada cliente usa um endereço próprio (
c1.localhost,c2.localhost…) para o navegador não enfileirar as ligações. Chrome, Edge e Firefox entendem esses endereços. O Safari não. - O terminal mostra códigos como
[92m. São as cores do log num terminal antigo. Não atrapalham a demo. No Windows 11, o app Terminal mostra as cores.
O que observar
Os dez clientes fazem um pedido a cada 10 segundos, todos no mesmo instante (:08, :18, :28…). Deixe cada estratégia rodar uns 2 minutos.
O servidor da demo aceita 1 requisição a cada 300 ms. Nos segundos terminados em 2, 3, 5 e 7 ele trava, e o cliente desiste em 2 segundos. Esses números são da demo, não da Clicksign.
| Estratégia | Atendidos | Ligações por pedido | O que dá para ver |
|---|---|---|---|
| Sem retry | 10% | 1,0 | Um cliente é atendido por rodada. Os outros nove levam 429. |
| Retry imediato | 53% | 7,6 | A taxa sobe, mas todo mundo liga de novo na hora e o servidor recebe uma rajada. |
| Backoff exponencial | 90% | 4,4 | A espera é 1, 2 e 4 s, mas todos juntos. A rajada só muda de lugar. |
| Backoff + jitter | ~100% | 3,0 | Cada cliente sorteia a espera. As ligações se espalham e quase todos são atendidos. |
Os números variam um pouco a cada rodada. A ordem se repete. Em http://localhost:8013/laboratorio/ dá para mudar tentativas, espera e jitter com controles deslizantes.
O código de cada estratégia
Cada estratégia é um arquivo curto em web/clientes/. O arquivo comum.js faz a chamada, com timeout de 2 segundos, e trata 429 e timeout como falha que a estratégia pode tentar de novo.
Sem retry
import { tentar } from "./comum.js";
export async function fazerPedido() {
return tentar();
}Retry imediato
import { tentar } from "./comum.js";
const MAXIMO_DE_TENTATIVAS = 10;
export async function fazerPedido() {
for (let tentativa = 1; tentativa <= MAXIMO_DE_TENTATIVAS; tentativa++) {
try {
return await tentar();
} catch (erro) {
if (tentativa === MAXIMO_DE_TENTATIVAS) throw erro;
}
}
}Backoff exponencial
import { tentar, esperar } from "./comum.js";
const MAXIMO_DE_TENTATIVAS = 10;
const ESPERA_INICIAL_MS = 1000;
const ESPERA_MAXIMA_MS = 4000;
export async function fazerPedido() {
for (let tentativa = 1; tentativa <= MAXIMO_DE_TENTATIVAS; tentativa++) {
try {
return await tentar();
} catch (erro) {
if (tentativa === MAXIMO_DE_TENTATIVAS) throw erro;
const espera = ESPERA_INICIAL_MS * 2 ** (tentativa - 1);
await esperar(Math.min(espera, ESPERA_MAXIMA_MS));
}
}
}Backoff exponencial com jitter
import { tentar, esperar } from "./comum.js";
const MAXIMO_DE_TENTATIVAS = 10;
const ESPERA_INICIAL_MS = 1000;
const ESPERA_MAXIMA_MS = 4000;
export async function fazerPedido() {
for (let tentativa = 1; tentativa <= MAXIMO_DE_TENTATIVAS; tentativa++) {
try {
return await tentar();
} catch (erro) {
if (tentativa === MAXIMO_DE_TENTATIVAS) throw erro;
const espera = ESPERA_INICIAL_MS * 2 ** (tentativa - 1);
const jitter = 0.5 + Math.random();
await esperar(Math.min(espera, ESPERA_MAXIMA_MS) * jitter);
}
}
}O jitter aqui sorteia entre 0,5 e 1,5 vezes a espera. Com espera de 2 segundos, a próxima tentativa sai entre 1 e 3 segundos, e cada cliente num instante diferente.
Para aprofundar
❓Precisa de ajuda? Entre em contato com o Suporte
💰Dúvida sobre planos e preços? Veja o comparativo
🔍Não sabe qual versão está usando? Descubra a sua versão
📚Respostas rápidas? Visite nosso FAQ
Updated about 24 hours ago