Como implementar uma fila de requisições para consultas de CPF em lote

Implemente uma fila de requisições para consultar CPFs em lote de forma eficiente. Controle custos de excedentes e processe grandes volumes sem erros.

Redação CPFHub.io
Redação CPFHub.io
··6 min de leitura
Como implementar uma fila de requisições para consultas de CPF em lote

Para consultar CPFs em lote com controle de custo, implemente uma fila de requisições que processa as consultas de forma ordenada, espaçando as chamadas à API e tratando falhas automaticamente — evitando disparar centenas de consultas de uma vez e incorrer em cobranças de excedente desnecessárias.

Introdução

Consultar CPFs em lote é uma necessidade frequente em operações de atualização cadastral, migração de dados e validação de bases. Enviar todas as requisições simultaneamente, no entanto, resulta em erros de timeout, consumo acelerado da cota mensal e custos de excedente difíceis de controlar. A solução é implementar uma fila de requisições que processa as consultas de forma ordenada, respeitando o ritmo da API e tratando falhas automaticamente.


Por que usar filas para consultas em lote

O processamento direto sem fila causa problemas previsíveis:

  • Consumo descontrolado de cota -- disparar todas as requisições de uma vez esgota o limite mensal rapidamente e gera cobranças de excedente (R$0,15 por consulta adicional)
  • Timeout em cascata -- muitas conexões simultâneas aumentam a latência de todas as requisições
  • Perda de progresso -- se o script falhar no meio, não há como retomar de onde parou
  • Requisições desperdiçadas -- falhas de rede e timeouts consomem tentativas sem resultado útil
  • Sobrecarga do servidor -- picos de requisições prejudicam a experiência de todos os usuários da API

A fila resolve tudo isso ao serializar e espaçar as chamadas, dando ao sistema previsibilidade de custo e confiabilidade de resultado.


Arquitetura da fila de processamento

A fila deve gerenciar o ciclo de vida completo de cada requisição:

ComponenteResponsabilidadeTecnologia sugerida
ProducerEnfileirar CPFs para consultaScript de importação
QueueArmazenar requisições pendentesRedis / arquivo JSON
WorkerProcessar requisições uma a umaConsumer com rate limit
Rate LimiterControlar frequência de chamadasToken bucket / sleep
Dead Letter QueueArmazenar falhas para reprocessamentoFila secundária
Result StoreSalvar resultados processadosBanco de dados / CSV

Implementação completa com Python

import requests
import json
import time
from collections import deque
from datetime import datetime
from pathlib import Path

class CPFBatchQueue:
    def __init__(self, api_key: str, rate_limit_per_sec: float = 2):
        self.api_key = api_key
        self.intervalo = 1.0 / rate_limit_per_sec
        self.fila = deque()
        self.resultados = []
        self.falhas = deque()
        self.max_retries = 3
        self.arquivo_progresso = Path("progresso_lote.json")

    def enfileirar(self, cpfs: list):
        for cpf in cpfs:
            cpf_limpo = cpf.replace(".", "").replace("-", "").strip()
            if len(cpf_limpo) == 11:
                self.fila.append({"cpf": cpf_limpo, "tentativas": 0})
        print(f"{len(self.fila)} CPFs enfileirados para processamento")

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

        if response.status_code == 200:
            dados = response.json()
            if dados["success"]:
                return {
                    "status": "OK",
                    "cpf": dados["data"]["cpf"],
                    "nome": dados["data"]["name"],
                    "nascimento": dados["data"]["birthDate"],
                    "genero": dados["data"]["gender"]
                }
            return {"status": "NAO_ENCONTRADO", "cpf": cpf}
        else:
            return {"status": "ERRO", "cpf": cpf, "http": response.status_code}

    def processar(self):
        total = len(self.fila)
        processados = 0

        print(f"Iniciando processamento de {total} CPFs...")
        print(f"Cadência: {1/self.intervalo:.0f} req/seg")
        print("=" * 50)

        while self.fila:
            item = self.fila.popleft()
            resultado = self.consultar(item["cpf"])

            if resultado["status"] == "ERRO":
                item["tentativas"] += 1
                if item["tentativas"] < self.max_retries:
                    self.fila.append(item)
                    time.sleep(self.intervalo * 3)  # Backoff
                else:
                    self.falhas.append(item)
            else:
                self.resultados.append(resultado)

            processados += 1
            if processados % 10 == 0:
                self.salvar_progresso()
                print(f"Progresso: {processados}/{total} "
                        f"({(processados/total)*100:.1f}%)")

            time.sleep(self.intervalo)

        self.salvar_progresso()
        self.relatorio_final(total)

    def salvar_progresso(self):
        with open(self.arquivo_progresso, "w") as f:
            json.dump({
                "timestamp": datetime.now().isoformat(),
                "processados": len(self.resultados),
                "pendentes": len(self.fila),
                "falhas": len(self.falhas)
            }, f, indent=2)

    def relatorio_final(self, total):
        ok = sum(1 for r in self.resultados if r["status"] == "OK")
        nao_encontrados = sum(1 for r in self.resultados if r["status"] == "NAO_ENCONTRADO")
        print("\n" + "=" * 50)
        print(f"Total processados: {len(self.resultados)}")
        print(f"Encontrados: {ok}")
        print(f"Não encontrados: {nao_encontrados}")
        print(f"Falhas definitivas:{len(self.falhas)}")

# Uso
fila = CPFBatchQueue("SUA_CHAVE_AQUI", rate_limit_per_sec=2)
fila.enfileirar(["12345678909", "98765432100", "11122233344"])
fila.processar()

Nota de custo: a API CPFHub.io não bloqueia ao exceder o plano — cada consulta além da cota mensal é cobrada a R$0,15. Espaçar as requisições com a fila é a forma mais eficiente de manter o custo sob controle e evitar surpresas na fatura.


Estratégias de retry e backoff

Quando a API retorna erro, a estratégia de retry determina a eficiência da recuperação:

  • Retry imediato -- apenas para erros de rede transitórios (timeout, connection reset)
  • Backoff linear -- aumentar o intervalo em incrementos fixos (1s, 2s, 3s) para erros persistentes
  • Backoff exponencial -- dobrar o intervalo a cada tentativa (1s, 2s, 4s, 8s) para erros recorrentes
  • Jitter aleatório -- adicionar variação aleatória ao intervalo para evitar thundering herd
  • Dead letter queue -- após N tentativas, mover o item para uma fila separada de análise manual

Otimizações para grandes volumes

Para processamentos com milhares ou milhões de CPFs:

  • Deduplicação prévia -- remova CPFs duplicados antes de enfileirar para economizar cota
  • Workers paralelos -- execute múltiplos workers respeitando um budget de requisições global compartilhado
  • Checkpoint periódico -- salve o estado da fila a cada N processamentos para permitir retomada
  • Horários estratégicos -- execute lotes grandes em períodos de menor tráfego para minimizar latência
  • Priorização -- ordene a fila por criticidade, processando primeiro os CPFs mais urgentes

Perguntas frequentes

Por que usar uma fila em vez de disparar todas as consultas de uma vez?

Disparar centenas de consultas simultaneamente esgota a cota mensal rapidamente e gera cobranças de excedente (R$0,15 por consulta além do plano). A fila serializa as chamadas em um ritmo controlado, tornando o custo previsível e o processo retomável em caso de falha.

A API CPFHub.io bloqueia requisições em lote?

Não. A API nunca bloqueia nem retorna HTTP 429 por excesso de volume. O que acontece ao ultrapassar o plano é a cobrança automática de R$0,15 por consulta adicional. A fila não serve para evitar bloqueio — serve para controlar o custo dessas cobranças extras.

Como retomar um lote interrompido no meio?

Salve o progresso periodicamente em um arquivo JSON com a lista de CPFs já processados e os ainda pendentes. Ao reiniciar, carregue o checkpoint e enfileire apenas os pendentes. O exemplo Python acima já implementa essa lógica com salvar_progresso() a cada 10 consultas.

Qual cadência de requisições é recomendada para lotes grandes?

Depende do volume e do prazo. Para 1.000 CPFs em um dia, 1 req/s é suficiente e consome apenas ~17 minutos. Para 10.000 CPFs, considere 2–5 req/s com workers paralelos e um budget diário calculado para não exceder o excedente aceitável do plano contratado.


Conclusão

Uma fila de requisições bem implementada transforma consultas caóticas em um processo ordenado, previsível e econômico. Com cadência controlada, retry inteligente e checkpoint de progresso, você processa grandes volumes de CPFs sem desperdiçar cota nem gerar cobranças de excedente desnecessárias. Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e valide CPFs em lote com custo totalmente sob controle.

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