# 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.

**Publicado:** 08/04/2025
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/implementar-fila-requisicoes-consultas-cpf-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:

| Componente | Responsabilidade | Tecnologia sugerida |
|---|---|---|
| Producer | Enfileirar CPFs para consulta | Script de importação |
| Queue | Armazenar requisições pendentes | Redis / arquivo JSON |
| Worker | Processar requisições uma a uma | Consumer com rate limit |
| Rate Limiter | Controlar frequência de chamadas | Token bucket / sleep |
| Dead Letter Queue | Armazenar falhas para reprocessamento | Fila secundária |
| Result Store | Salvar resultados processados | Banco de dados / CSV |

---

## Implementação completa com Python

```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.

### Leia também

- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)
- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Onboarding digital em fintechs: como validar CPF em menos de 30 segundos](https://cpfhub.io/blog/onboarding-digital-em-fintechs-como-validar-cpf-em-menos-de-30-segundos)
- [KYC no Brasil: quais setores são obrigados a validar CPF por lei](https://cpfhub.io/blog/kyc-no-brasil-quais-setores-sao-obrigados-a-validar-cpf-por-lei)

---

## 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](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e valide CPFs em lote com custo totalmente sob controle.

