Como usar Oban para processar consultas de CPF em background no Elixir

Use Oban para processar consultas de CPF em background no Elixir com filas, retry automático e agendamento.

Redação CPFHub.io
Redação CPFHub.io
··6 min de leitura
Como usar Oban para processar consultas de CPF em background no Elixir

Usar o Oban para processar consultas de CPF em background no Elixir garante que nenhuma consulta se perca em caso de falha, mesmo com alto volume de requisições. Com filas persistentes no PostgreSQL, retry automático e agendamento nativo, o Oban torna o processamento assíncrono da API CPFHub.io confiável e observável. A documentação oficial do Oban está disponível em hexdocs.pm/oban.

Introdução

Processar consultas de CPF em background é essencial quando o volume de requisições é alto ou quando a resposta da API não precisa ser síncrona. O Oban é a solução mais robusta para processamento em background no Elixir, oferecendo filas persistentes com PostgreSQL, retry automático, agendamento e monitoramento.


Configurando o Oban

Adicione o Oban ao projeto e configure as filas:

# mix.exs
defp deps do
    [
    {:oban, "~> 2.17"},
    {:httpoison, "~> 2.0"},
    {:jason, "~> 1.4"}
    ]
end

# config/config.exs
config :minha_app, Oban,
    repo: MinhaApp.Repo,
    queues: [cpf_consultas: 5, cpf_lote: 2],
    plugins: [
    Oban.Plugins.Pruner,
    {Oban.Plugins.Cron, crontab: []}
    ]

Execute a migration do Oban para criar as tabelas necessárias:

# Terminal
# mix ecto.gen.migration add_oban_jobs_table
# Na migration gerada:
defmodule MinhaApp.Repo.Migrations.AddObanJobsTable do
    use Ecto.Migration

    def up, do: Oban.Migration.up(version: 12)
    def down, do: Oban.Migration.down(version: 1)
end
FilaConcorrênciaUso
cpf_consultas5 workersConsultas individuais
cpf_lote2 workersProcessamento em lote

Criando o worker de consulta

O worker do Oban define como cada job de consulta de CPF será processado. Note que a API CPFHub.io nunca retorna HTTP 429 — ao atingir o limite do plano, ela cobra R$0,15 por consulta adicional sem bloquear requisições:

defmodule MinhaApp.Workers.CpfConsultaWorker do
    use Oban.Worker,
    queue: :cpf_consultas,
    max_attempts: 3,
    priority: 1

    @base_url "https://api.cpfhub.io"

    @impl Oban.Worker
    def perform(%Oban.Job{args: %{"cpf" => cpf, "callback_url" => callback_url} = args}) do
    api_key = Application.get_env(:minha_app, :cpfhub_api_key)
    headers = [{"x-api-key", api_key}]

    case HTTPoison.get("#{@base_url}/cpf/#{cpf}", headers, recv_timeout: 10_000) do
    {:ok, %{status_code: 200, body: body}} ->
    resultado = Jason.decode!(body)
    processar_resultado(cpf, resultado, callback_url)
    :ok

    {:ok, %{status_code: status}} ->
    {:error, "API retornou status #{status}"}

    {:error, %{reason: reason}} ->
    {:error, "Falha na requisição: #{inspect(reason)}"}
    end
    end

    defp processar_resultado(cpf, %{"success" => true, "data" => data}, callback_url) do
    resultado = %{
    cpf: cpf,
    nome: data["name"],
    data_nascimento: data["birthDate"],
    genero: data["gender"],
    status: "encontrado",
    processado_em: DateTime.utc_now()
    }

    if callback_url do
    HTTPoison.post(callback_url, Jason.encode!(resultado),
    [{"Content-Type", "application/json"}])
    end

    MinhaApp.Cpf.salvar_resultado(resultado)
    end

    defp processar_resultado(cpf, _, _callback_url) do
    MinhaApp.Cpf.salvar_resultado(%{cpf: cpf, status: "nao_encontrado"})
    end
end

Worker de processamento em lote

Para processar múltiplos CPFs, crie um worker que divide o trabalho em jobs individuais:

defmodule MinhaApp.Workers.CpfLoteWorker do
    use Oban.Worker,
    queue: :cpf_lote,
    max_attempts: 1,
    unique: [period: 300]

    alias MinhaApp.Workers.CpfConsultaWorker

    @impl Oban.Worker
    def perform(%Oban.Job{args: %{"cpfs" => cpfs, "lote_id" => lote_id}}) do
    jobs = Enum.map(cpfs, fn cpf ->
    CpfConsultaWorker.new(%{
    cpf: cpf,
    lote_id: lote_id,
    callback_url: nil
    })
    end)

    Oban.insert_all(jobs)
    :ok
    end
end

Enfileirando jobs

Crie funções de conveniência para enfileirar consultas:

defmodule MinhaApp.Cpf.Enqueuer do
    alias MinhaApp.Workers.{CpfConsultaWorker, CpfLoteWorker}

    def consultar_async(cpf, opts \\ []) do
    callback_url = Keyword.get(opts, :callback_url)
    prioridade = Keyword.get(opts, :prioridade, 1)
    agendar_em = Keyword.get(opts, :agendar_em)

    args = %{cpf: cpf, callback_url: callback_url}

    worker_opts = [priority: prioridade]
    worker_opts = if agendar_em, do: [{:scheduled_at, agendar_em} | worker_opts], else: worker_opts

    args
    |> CpfConsultaWorker.new(worker_opts)
    |> Oban.insert()
    end

    def processar_lote(cpfs) do
    lote_id = Ecto.UUID.generate()

    %{cpfs: cpfs, lote_id: lote_id}
    |> CpfLoteWorker.new()
    |> Oban.insert()

    {:ok, lote_id}
    end

    def consultar_agendado(cpf, data_hora) do
    consultar_async(cpf, agendar_em: data_hora)
    end
end

# Uso
MinhaApp.Cpf.Enqueuer.consultar_async("12345678900",
    callback_url: "https://meuapp.com/webhook/cpf"
)

MinhaApp.Cpf.Enqueuer.processar_lote([
    "12345678900", "98765432100", "11122233344"
])

# Agendar para daqui a 1 hora
MinhaApp.Cpf.Enqueuer.consultar_agendado(
    "12345678900",
    DateTime.add(DateTime.utc_now(), 3600, :second)
)

Monitorando jobs

Acompanhe o status dos jobs de consulta de CPF:

defmodule MinhaApp.Cpf.Monitor do
    import Ecto.Query
    alias MinhaApp.Repo

    def estatisticas do
    query = from j in Oban.Job,
    where: j.worker == "MinhaApp.Workers.CpfConsultaWorker",
    group_by: j.state,
    select: {j.state, count(j.id)}

    stats = Repo.all(query) |> Map.new()

    %{
    pendentes: Map.get(stats, "available", 0),
    executando: Map.get(stats, "executing", 0),
    concluidos: Map.get(stats, "completed", 0),
    com_erro: Map.get(stats, "retryable", 0) + Map.get(stats, "discarded", 0),
    agendados: Map.get(stats, "scheduled", 0)
    }
    end

    def jobs_com_erro do
    query = from j in Oban.Job,
    where: j.worker == "MinhaApp.Workers.CpfConsultaWorker",
    where: j.state in ["retryable", "discarded"],
    order_by: [desc: j.inserted_at],
    limit: 20

    Repo.all(query)
    end
end

Perguntas frequentes

O que é necessário para implementar consultas de CPF assíncronas com Oban?

Você precisa do Oban configurado com um repo PostgreSQL, de um worker que chama GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key, e de uma função de enfileiramento. O Oban cuida do retry automático em caso de falha de rede, garantindo que nenhuma consulta se perca.

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. 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 — portanto, não há necessidade de lógica de back-off por rate limit.

Como definir o número ideal de workers por fila no Oban?

O número de workers (concurrency) deve ser calibrado com base na latência da API (~900ms) e no throughput desejado. Para 5 workers na fila cpf_consultas, você consegue processar aproximadamente 300 consultas por minuto. Monitore a fila com MinhaApp.Cpf.Monitor.estatisticas/0 e ajuste conforme o volume real.

Como garantir conformidade com a LGPD no processamento em background?

Garanta que os dados de CPF nos args do job sejam mascarados nos logs do Oban, defina um max_attempts razoável para evitar reprocessamentos desnecessários, e implemente um período de retenção para jobs concluídos usando Oban.Plugins.Pruner. Documente a finalidade de cada fila para atender ao artigo 37 da LGPD.


Conclusão

O Oban transforma o processamento de consultas de CPF em uma operação confiável e observável. Com filas persistentes, retry automático, agendamento e monitoramento, você garante que nenhuma consulta se perca, mesmo em caso de falhas de rede ou reinicializações da aplicação.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a integrar consultas de CPF em background na sua aplicação Elixir com Oban hoje mesmo.

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