Como Implementar Rate Limiting e Exponential Backoff ao Consumir APIs de CPF

Aprenda a implementar rate limiting e exponential backoff ao consumir APIs de CPF. Guia com exemplos em Python e JavaScript para produção.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como Implementar Rate Limiting e Exponential Backoff ao Consumir APIs de CPF

Rate limiting no cliente e exponential backoff são padrões complementares que tornam seu sistema resiliente ao consumir APIs de CPF: o rate limiter controla o ritmo das requisições para preservar sua cota mensal, enquanto o backoff exponencial com jitter garante recuperação elegante em falhas de rede ou indisponibilidade temporária do servidor.

Introdução

Ao integrar a API de CPF do CPFHub.io, implementar rate limiting no lado do cliente e exponential backoff para retentativas são práticas essenciais que preservam sua cota de consultas, reduzem erros transitórios e tornam seu sistema mais resiliente. Essas técnicas são padrões de engenharia aplicáveis a qualquer API REST e ficam ainda mais relevantes quando o volume de consultas impacta diretamente o faturamento.


Entendendo rate limiting do lado do servidor

Antes de implementar o controle do lado do cliente, é importante entender como APIs comunicam seus limites através de headers de resposta.

HeaderSignificadoExemplo
X-RateLimit-LimitRequisições permitidas por janela100
X-RateLimit-RemainingRequisições restantes na janela47
X-RateLimit-ResetTimestamp de reset da janela1704110400
Retry-AfterSegundos para esperar após erro30
# Python - Lendo headers de rate limit
import requests
import time

def consultar_com_awareness(cpf: str, api_key: str) -> dict:
    response = requests.get(
    f"https://api.cpfhub.io/cpf/{cpf}",
    headers={"x-api-key": api_key}
    )

    remaining = int(response.headers.get("X-RateLimit-Remaining", 100))
    reset_time = int(response.headers.get("X-RateLimit-Reset", 0))

    if remaining < 10:
    wait_time = max(0, reset_time - int(time.time()))
    print(f"Atenção: apenas {remaining} requisições restantes. "
    f"Reset em {wait_time}s")

    response.raise_for_status()
    return response.json()
  • X-RateLimit-Remaining -- monitore este header para desacelerar proativamente antes de atingir o limite
  • Retry-After -- em caso de erro de servidor, respeite este valor antes de tentar novamente
  • Reset timestamp -- permite calcular exatamente quando a janela de rate limit reinicia

Implementando rate limiter no cliente (Python)

Controlar a taxa de requisições do lado do cliente preserva sua cota mensal e melhora a previsibilidade do processamento.

import time
import threading
from collections import deque

class RateLimiter:
    def __init__(self, max_requests: int, window_seconds: float):
    self.max_requests = max_requests
    self.window = window_seconds
    self.timestamps = deque()
    self.lock = threading.Lock()

    def acquire(self):
    with self.lock:
    now = time.monotonic()

    # Remover timestamps fora da janela
    while self.timestamps and self.timestamps[0] <= now - self.window:
    self.timestamps.popleft()

    if len(self.timestamps) >= self.max_requests:
    wait_time = self.timestamps[0] + self.window - now
    time.sleep(wait_time)
    return self.acquire()

    self.timestamps.append(now)

class CPFClientComLimite:
    def __init__(self, api_key: str, max_rps: int = 10):
    self.api_key = api_key
    self.limiter = RateLimiter(max_requests=max_rps, window_seconds=1.0)
    self.session = requests.Session()
    self.session.headers["x-api-key"] = api_key

    def consultar(self, cpf: str) -> dict:
    self.limiter.acquire()
    response = self.session.get(
    f"https://api.cpfhub.io/cpf/{cpf}",
    timeout=15
    )
    response.raise_for_status()
    return response.json()

    def consultar_lote(self, cpfs: list) -> list:
    resultados = []
    for i, cpf in enumerate(cpfs):
    try:
    resultado = self.consultar(cpf)
    resultados.append({"cpf": cpf, "dados": resultado, "erro": None})
    except Exception as e:
    resultados.append({"cpf": cpf, "dados": None, "erro": str(e)})

    if (i + 1) % 50 == 0:
    print(f"Processados {i + 1}/{len(cpfs)} CPFs")

    return resultados
ConfiguraçãoValorEfeito
max_rps=1010 req/sConservador, nunca atinge rate limit
max_rps=5050 req/sModerado, monitora remaining
max_rps=100100 req/sAgressivo, precisa de backoff
  • Sliding window -- controle baseado em janela deslizante é mais preciso que contadores simples
  • Thread-safe -- o lock garante que o rate limiter funcione corretamente em ambientes multi-thread
  • Processamento em lote -- o rate limiter gerencia automaticamente o ritmo das requisições

Implementando rate limiter no cliente (JavaScript)

Em JavaScript, o rate limiter precisa funcionar com a event loop assíncrona.

class RateLimiter {
    constructor(maxRequests, windowMs) {
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
    this.timestamps = [];
    this.queue = [];
    }

    async acquire() {
    return new Promise((resolve) => {
    this.queue.push(resolve);
    this.#process();
    });
    }

    #process() {
    const now = Date.now();
    this.timestamps = this.timestamps.filter(
    (t) => t > now - this.windowMs
    );

    while (this.queue.length > 0 && this.timestamps.length < this.maxRequests) {
    this.timestamps.push(now);
    const resolve = this.queue.shift();
    resolve();
    }

    if (this.queue.length > 0) {
    const oldestTimestamp = this.timestamps[0];
    const waitTime = oldestTimestamp + this.windowMs - now;
    setTimeout(() => this.#process(), Math.max(waitTime, 10));
    }
    }
}

class CPFClientComLimite {
    constructor(apiKey, maxRPS = 10) {
    this.apiKey = apiKey;
    this.limiter = new RateLimiter(maxRPS, 1000);
    this.baseUrl = "https://api.cpfhub.io/cpf";
    }

    async consultar(cpf) {
    await this.limiter.acquire();

    const response = await fetch(`${this.baseUrl}/${cpf.replace(/\D/g, "")}`, {
    headers: { "x-api-key": this.apiKey },
    });

    if (!response.ok) {
    throw new Error(`HTTP ${response.status}`);
    }

    return response.json();
    }

    async consultarLote(cpfs) {
    const resultados = [];
    for (const cpf of cpfs) {
    try {
    const dados = await this.consultar(cpf);
    resultados.push({ cpf, dados, erro: null });
    } catch (error) {
    resultados.push({ cpf, dados: null, erro: error.message });
    }
    }
    return resultados;
    }
}
  • Promise queue -- requisições aguardam sua vez em uma fila quando o limite é atingido
  • setTimeout -- agenda a próxima verificação para quando a janela reiniciar
  • Processamento sequencial -- em lote, cada requisição respeita o rate limit automaticamente

Exponential backoff com jitter

Quando um retry é necessário por falha de rede ou erro de servidor, o backoff exponencial com jitter distribui as retentativas de forma inteligente, segundo as boas práticas de retry recomendadas pela AWS.

import random
import time

def exponential_backoff_retry(
    func,
    max_tentativas: int = 5,
    base_delay: float = 1.0,
    max_delay: float = 60.0,
    jitter_strategy: str = "full"
):
    for tentativa in range(max_tentativas):
    try:
    return func()
    except Exception as e:
    if tentativa == max_tentativas - 1:
    raise

    # Calcular delay com backoff exponencial
    delay = min(base_delay * (2 ** tentativa), max_delay)

    # Aplicar jitter
    if jitter_strategy == "full":
    delay = random.uniform(0, delay)
    elif jitter_strategy == "equal":
    delay = delay / 2 + random.uniform(0, delay / 2)
    elif jitter_strategy == "decorrelated":
    delay = random.uniform(base_delay, delay * 3)

    print(f"Tentativa {tentativa + 1} falhou: {e}. "
    f"Aguardando {delay:.1f}s")
    time.sleep(delay)

# Uso com consulta de CPF
client = CPFClientComLimite(api_key="sua-chave", max_rps=10)

resultado = exponential_backoff_retry(
    lambda: client.consultar("12345678909"),
    max_tentativas=3,
    base_delay=1.0
)
Estratégia de jitterFórmulaQuando usar
Full jitterrandom(0, delay)Padrão recomendado pela AWS
Equal jitterdelay/2 + random(0, delay/2)Quando precisa de delay mínimo
Decorrelatedrandom(base, delay*3)Cenários de alta contenção
Sem jitterdelay fixoNunca em produção
  • Full jitter -- a estratégia mais recomendada, distribui retentativas uniformemente
  • max_delay -- cap no delay máximo para evitar esperas absurdas após muitas falhas
  • Decorrelated jitter -- cada retry é independente do anterior, reduzindo sincronização

Perguntas frequentes

A API da CPFHub.io retorna HTTP 429 quando o limite de consultas é atingido?

Não. A API da CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições. Ao ultrapassar as 50 consultas mensais do plano gratuito (ou as 1.000 do plano Pro), cada consulta adicional é cobrada a R$ 0,15 automaticamente — o serviço continua disponível sem interrupção. O rate limiting descrito neste artigo é um padrão client-side para você controlar o ritmo das suas requisições e gerenciar sua cota, não uma resposta a bloqueios do servidor.

Por que implementar rate limiting no cliente se a API não bloqueia?

Porque o controle do lado do cliente serve a dois propósitos práticos: (1) distribuir o consumo ao longo do mês para evitar cobranças inesperadas de excedente, e (2) proteger sua infraestrutura de picos acidentais em processamentos em lote que poderiam gerar centenas de requisições em segundos. Trata-se de higiene de engenharia, não de uma obrigação imposta pelo servidor.

Quando o exponential backoff deve ser usado ao chamar a API de CPF?

O backoff exponencial é indicado para lidar com falhas de rede, timeouts e erros de servidor (5xx) — cenários transitórios onde a requisição pode ter sucesso em uma nova tentativa após breve espera. Para erros de CPF não encontrado (success: false) ou autenticação inválida (401), o retry não resolve: é necessário corrigir o dado ou a chave de API.

Qual é a latência esperada da API da CPFHub.io em produção?

A API da CPFHub.io responde em aproximadamente 900ms em condições normais. Ao configurar timeouts, use valores entre 10 e 15 segundos para absorver variações de rede sem tratar respostas legítimas como falhas. Com um rate limiter a 10 req/s, um lote de 1.000 CPFs processa em cerca de 100 segundos mais a latência de rede.


Conclusão

Rate limiting no cliente e exponential backoff são técnicas complementares que tornam seu sistema resiliente ao consumir APIs de CPF. O rate limiter preserva sua cota mensal e evita cobranças de excedente desnecessárias, enquanto o backoff exponencial com jitter garante recuperação elegante quando falhas de rede ou indisponibilidade temporária acontecem. Implemente ambas as técnicas desde o início do projeto e ajuste os parâmetros conforme os limites da sua conta.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e integre a API de CPF com os padrões de resiliência que seu sistema merece.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

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.

WhatsAppFale conosco via WhatsApp