Introdução
Nem toda falha na consulta de CPF é permanente. Timeouts, erros de rede e indisponibilidades temporárias são comuns em integrações com APIs externas. Um sistema de retry inteligente sabe diferenciar falhas temporárias de permanentes, aplica backoff exponencial para não sobrecarregar o provedor e envia consultas que esgotaram as tentativas para uma dead letter queue (DLQ) para reprocessamento posterior.
Anatomia de um retry inteligente
Nem toda falha merece retry. Erros 4xx geralmente indicam problemas no input e não vale a pena repetir. Já erros 5xx e timeouts são candidatos perfeitos para nova tentativa.
| Código HTTP | Tipo de erro | Deve fazer retry? | Justificativa |
|---|---|---|---|
| 400 | Bad Request | Não | Input inválido, retry não resolve |
| 401 | Unauthorized | Não | Credencial errada, precisa correção |
| 403 | Forbidden | Não | Sem permissão, precisa ajuste |
| 408 | Timeout | Sim | Temporário, servidor sobrecarregado |
| 429 | Rate Limit | Sim (com delay) | Esperar e tentar novamente |
| 500 | Internal Error | Sim | Erro no servidor, pode se resolver |
| 502/503 | Indisponível | Sim | Servidor temporariamente fora |
- Backoff exponencial -- cada retry espera progressivamente mais tempo (1s, 2s, 4s, 8s) para dar tempo ao servidor de se recuperar
- Jitter -- adiciona aleatoriedade ao tempo de espera para evitar que múltiplos clientes façam retry no mesmo instante
- Max retries -- limita o número de tentativas para não ficar em loop infinito
Implementando o retry com backoff exponencial
const axios = require("axios");
class RetryConfig {
constructor({
maxRetries = 3,
baseDelay = 1000,
maxDelay = 30000,
jitterFactor = 0.5,
retryableStatuses = [408, 429, 500, 502, 503, 504],
} = {}) {
this.maxRetries = maxRetries;
this.baseDelay = baseDelay;
this.maxDelay = maxDelay;
this.jitterFactor = jitterFactor;
this.retryableStatuses = retryableStatuses;
}
calculateDelay(attempt) {
const exponential = this.baseDelay * Math.pow(2, attempt);
const capped = Math.min(exponential, this.maxDelay);
const jitter = capped * this.jitterFactor * Math.random();
return capped + jitter;
}
isRetryable(error) {
if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") {
return true;
}
if (error.response) {
return this.retryableStatuses.includes(error.response.status);
}
return true; // Erros de rede são retryable
}
}
async function consultarCpfComRetry(cpf, config = new RetryConfig()) {
let lastError;
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
try {
const response = await axios.get(
`https://api.cpfhub.io/cpf/${cpf}`,
{
headers: { "x-api-key": process.env.CPFHUB_API_KEY },
timeout: 10000,
}
);
return response.data;
} catch (error) {
lastError = error;
if (!config.isRetryable(error) || attempt === config.maxRetries) {
break;
}
const delay = config.calculateDelay(attempt);
console.log(`Tentativa ${attempt + 1} falhou. Retry em ${delay}ms...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw lastError;
}
- calculateDelay -- implementa backoff exponencial com jitter para distribuir as retentativas no tempo
- isRetryable -- avalia se o erro é temporário e merece nova tentativa
- Loop controlado -- cada iteração incrementa o attempt e calcula um delay maior
Implementando a dead letter queue
Quando todas as tentativas de retry se esgotam, a consulta não deve ser simplesmente descartada. Uma DLQ armazena essas consultas falhadas para reprocessamento posterior.
const { Queue, Worker } = require("bullmq");
const Redis = require("ioredis");
const connection = new Redis({ host: "localhost", port: 6379 });
// Fila principal de consultas
const cpfQueue = new Queue("cpf-consultas", { connection });
// Dead Letter Queue
const cpfDLQ = new Queue("cpf-dlq", { connection });
// Worker que processa consultas
const worker = new Worker(
"cpf-consultas",
async (job) => {
const { cpf, requestId } = job.data;
try {
const resultado = await consultarCpfComRetry(cpf);
return resultado;
} catch (error) {
// Após esgotar retries, envia para DLQ
await cpfDLQ.add("consulta-falhada", {
cpf,
requestId,
error: error.message,
originalJobId: job.id,
failedAt: new Date().toISOString(),
attempts: job.attemptsMade,
});
throw error;
}
},
{
connection,
concurrency: 10,
limiter: { max: 100, duration: 60000 },
}
);
// Enfileirar uma consulta
async function enfileirarConsulta(cpf, requestId) {
await cpfQueue.add("consultar", { cpf, requestId }, {
attempts: 3,
backoff: { type: "exponential", delay: 2000 },
removeOnComplete: 1000,
removeOnFail: false,
});
}
- BullMQ -- biblioteca robusta para filas de trabalho com Redis, suporta retry nativo e prioridades
- DLQ dedicada -- fila separada que armazena jobs falhados com contexto completo do erro
- Limiter -- controla a taxa de requisições para respeitar rate limits da API
Reprocessando a dead letter queue
A DLQ não é um cemitério de mensagens. Ela precisa de um mecanismo de reprocessamento para tentar novamente as consultas quando o problema for resolvido.
// Worker da DLQ - reprocessa periodicamente
const dlqWorker = new Worker(
"cpf-dlq",
async (job) => {
const { cpf, requestId, failedAt } = job.data;
// Verifica se a consulta não é muito antiga
const horasDesdeAFalha =
(Date.now() - new Date(failedAt).getTime()) / 3600000;
if (horasDesdeAFalha > 24) {
console.log(`Job ${requestId} expirado (${horasDesdeAFalha}h)`);
return { status: "expired" };
}
// Tenta reprocessar com configuração mais tolerante
const resultado = await consultarCpfComRetry(
cpf,
new RetryConfig({ maxRetries: 5, baseDelay: 5000 })
);
return resultado;
},
{
connection,
concurrency: 2,
limiter: { max: 10, duration: 60000 },
}
);
// Métricas da DLQ
async function obterMetricasDLQ() {
const waiting = await cpfDLQ.getWaitingCount();
const failed = await cpfDLQ.getFailedCount();
return { pendentes: waiting, falhados: failed };
}
| Parâmetro DLQ | Valor recomendado | Motivo |
|---|---|---|
| Concurrency | 2-5 | Não sobrecarregar a API durante reprocessamento |
| TTL (expiração) | 24h | Consultas muito antigas podem ser irrelevantes |
| Rate limit | 10/min | Baixa prioridade, não competir com tráfego normal |
| Alerta | > 100 pendentes | Indica problema sistêmico que precisa de atenção |
Perguntas frequentes
O que é necessário para implementar validação de CPF neste contexto?
A validação de CPF exige uma chamada à API com o número do documento e a chave de autenticação. A CPFHub.io retorna o status do CPF, nome do titular e data de nascimento em menos de 200ms, permitindo a verificação em tempo real durante o cadastro ou transação.
A API CPFHub.io funciona para todos os volumes de consulta?
Sim. O plano gratuito oferece 50 consultas por mês sem cartão de crédito — ideal para testes e projetos pequenos. Para volumes maiores, o plano Pro inclui 1.000 consultas mensais por R$149. Se o limite for ultrapassado, a API não bloqueia: cobra R$0,15 por consulta adicional.
Como garantir conformidade com a LGPD ao usar uma API de CPF?
Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário (não guarde o CPF cru se um token bastar), implemente controle de acesso aos logs de consulta e documente a base legal para o tratamento. A ANPD orienta que dados de identificação devem ser tratados com o princípio da necessidade.
Quanto tempo leva para integrar a API CPFHub.io?
A integração básica leva menos de 30 minutos: crie uma conta em cpfhub.io, gere a API key no painel e faça uma chamada GET para https://api.cpfhub.io/cpf/{CPF} com o header x-api-key. A documentação inclui exemplos em Python, Node.js, PHP, Java e outras linguagens.
Conclusão
Um sistema de retry inteligente com dead letter queue garante que nenhuma consulta de CPF se perca, mesmo em cenários de falha. O backoff exponencial com jitter protege o provedor de sobrecarga, enquanto a DLQ preserva as consultas para reprocessamento posterior. Teste essa abordagem com a API do cpfhub.io.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



