Como Criar um Job Scheduler em Ruby para Processar Consultas de CPF Automaticamente

Aprenda a criar um job scheduler em Ruby para processar consultas de CPF automaticamente, com agendamento, retry e monitoramento.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como Criar um Job Scheduler em Ruby para Processar Consultas de CPF Automaticamente

Um job scheduler em Ruby permite agendar tarefas recorrentes de consulta e manutenção de CPF — como revalidar cadastros antigos, processar lotes pendentes e limpar caches expirados — de forma confiável e sem intervenção manual, usando Sidekiq-Cron para aplicações Rails ou Rufus-Scheduler para projetos independentes.

Introdução

Muitas operações com CPF precisam ser executadas de forma periódica e automática: revalidar cadastros antigos, processar lotes de novos clientes, limpar caches expirados ou gerar relatórios de conformidade. Um job scheduler em Ruby permite agendar essas tarefas para execução automática, garantindo que o processamento ocorra de forma confiável e sem intervenção manual.

Arquitetura do scheduler

O scheduler coordena a execução de jobs periódicos sem bloquear a aplicação principal.

ComponenteResponsabilidadeFerramenta
SchedulerDefine horários e frequência dos jobsSidekiq-Cron / Rufus-Scheduler
WorkerExecuta a lógica de cada jobSidekiq Worker
QueueGerencia jobs pendentes e em execuçãoRedis
MonitorAcompanha saúde dos jobsSidekiq Web UI
StoragePersiste resultadosPostgreSQL

Sidekiq-Cron -- ideal para aplicações Rails que já usam Sidekiq.

Rufus-Scheduler -- scheduler leve e independente de framework.

Whenever -- gera crontabs para agendamento no nível do sistema operacional.


Implementação com Sidekiq-Cron

Para aplicações Rails com Sidekiq, o sidekiq-cron oferece agendamento integrado.

# Gemfile
gem "sidekiq", "~> 7.0"
gem "sidekiq-cron", "~> 1.12"
gem "faraday", "~> 2.0"

# config/initializers/sidekiq_cron.rb
schedule = [
    {
    "name" => "Revalidar CPFs antigos - diario",
    "cron" => "0 2 * * *", # Todo dia às 2h
    "class" => "RevalidarCpfsAntigosWorker",
    "queue" => "agendado"
    },
    {
    "name" => "Processar fila de CPFs pendentes - a cada 5min",
    "cron" => "*/5 * * * *",
    "class" => "ProcessarCpfsPendentesWorker",
    "queue" => "agendado"
    },
    {
    "name" => "Limpar consultas expiradas - semanal",
    "cron" => "0 3 * * 0", # Domingo às 3h
    "class" => "LimparConsultasExpiradasWorker",
    "queue" => "manutencao"
    },
    {
    "name" => "Relatorio de consultas - mensal",
    "cron" => "0 6 1 * *", # Dia 1 às 6h
    "class" => "RelatorioConsultasWorker",
    "queue" => "relatorios"
    }
]

Sidekiq::Cron::Job.load_from_array!(schedule)

Workers para cada tipo de job

Cada worker implementa a lógica específica do seu tipo de processamento.

# app/workers/revalidar_cpfs_antigos_worker.rb
class RevalidarCpfsAntigosWorker
    include Sidekiq::Worker
    sidekiq_options queue: :agendado, retry: 3

    LIMITE_DIARIO = 500
    DIAS_PARA_REVALIDAR = 30

    def perform
    cpfs_antigos = ConsultaCpf
    .where(status: "sucesso")
    .where("consultado_em < ?", DIAS_PARA_REVALIDAR.days.ago)
    .order(consultado_em: :asc)
    .limit(LIMITE_DIARIO)

    logger.info(
    "[Revalidar] Iniciando revalidacao de #{cpfs_antigos.count} CPFs"
    )

    cliente = build_api_client
    resultados = { sucesso: 0, falha: 0, erro: 0 }

    cpfs_antigos.find_each do |consulta|
    resultado = revalidar_cpf(cliente, consulta)
    resultados[resultado] += 1
    sleep(0.2) # Respeitar rate limit
    end

    logger.info("[Revalidar] Concluido: #{resultados}")
    end

    private

    def build_api_client
    Faraday.new(url: "https://api.cpfhub.io") do |conn|
    conn.headers["x-api-key"] = ENV["CPFHUB_API_KEY"]
    conn.options.timeout = 10
    conn.adapter Faraday.default_adapter
    end
    end

    def revalidar_cpf(cliente, consulta)
    cpf = consulta.cpf_cifrado
    resposta = cliente.get("/cpf/#{cpf}")
    dados = JSON.parse(resposta.body)

    if dados["success"]
    consulta.update!(
    nome: dados["data"]["name"],
    genero: dados["data"]["gender"],
    data_nascimento: dados["data"]["birthDate"],
    consultado_em: Time.current,
    expira_em: 24.hours.from_now,
    status: "sucesso"
    )
    :sucesso
    else
    consulta.update!(status: "falha", motivo_falha: "Nao encontrado na revalidacao")
    :falha
    end
    rescue StandardError => e
    logger.error("[Revalidar] Erro no CPF #{consulta.id}: #{e.message}")
    :erro
    end
end

# app/workers/processar_cpfs_pendentes_worker.rb
class ProcessarCpfsPendentesWorker
    include Sidekiq::Worker
    sidekiq_options queue: :agendado, retry: 2

    def perform
    pendentes = ConsultaCpf.where(status: "pendente").limit(100)
    return if pendentes.empty?

    logger.info("[Pendentes] Processando #{pendentes.count} CPFs pendentes")

    cliente = Faraday.new(url: "https://api.cpfhub.io") do |conn|
    conn.headers["x-api-key"] = ENV["CPFHUB_API_KEY"]
    conn.options.timeout = 10
    conn.adapter Faraday.default_adapter
    end

    pendentes.find_each do |consulta|
    resposta = cliente.get("/cpf/#{consulta.cpf_cifrado}")
    dados = JSON.parse(resposta.body)

    if dados["success"]
    consulta.update!(
    nome: dados["data"]["name"],
    genero: dados["data"]["gender"],
    data_nascimento: dados["data"]["birthDate"],
    status: "sucesso",
    consultado_em: Time.current,
    expira_em: 24.hours.from_now
    )
    else
    consulta.update!(status: "falha", motivo_falha: "Nao encontrado")
    end

    sleep(0.1)
    rescue StandardError => e
    consulta.update!(status: "falha", motivo_falha: e.message)
    end
    end
end

Scheduler independente com Rufus

Para aplicações fora do Rails ou que precisam de um scheduler independente.

require "rufus-scheduler"
require "faraday"
require "json"

scheduler = Rufus::Scheduler.new

# Job a cada 5 minutos: processar CPFs pendentes
scheduler.every "5m", first: :now do
    puts "[#{Time.now}] Verificando CPFs pendentes..."
    processar_pendentes
end

# Job diário às 2h: revalidar CPFs antigos
scheduler.cron "0 2 * * *" do
    puts "[#{Time.now}] Iniciando revalidacao diaria..."
    revalidar_antigos
end

# Job semanal: gerar relatório
scheduler.cron "0 6 * * 1" do
    puts "[#{Time.now}] Gerando relatorio semanal..."
    gerar_relatorio
end

def processar_pendentes
    # Lógica de processamento
end

def revalidar_antigos
    # Lógica de revalidação
end

def gerar_relatorio
    # Lógica de relatório
end

scheduler.join
Expressão CronFrequênciaUso Típico
*/5 * * * *A cada 5 minutosProcessar CPFs pendentes
0 2 * * *Diariamente às 2hRevalidar CPFs antigos
0 3 * * 0Domingos às 3hLimpeza de registros expirados
0 6 1 * *Dia 1 de cada mês às 6hRelatórios mensais
0 */4 * * *A cada 4 horasSincronização de dados

Monitoramento e alertas

Monitore a saúde dos jobs agendados para detectar falhas rapidamente. A Lei Geral de Proteção de Dados (LGPD) exige que sistemas que tratam dados pessoais mantenham logs e mecanismos de rastreabilidade — o relatório mensal gerado pelo worker é uma forma prática de demonstrar conformidade.

# app/workers/relatorio_consultas_worker.rb
class RelatorioConsultasWorker
    include Sidekiq::Worker
    sidekiq_options queue: :relatorios, retry: 1

    def perform
    periodo = 1.month.ago..Time.current

    metricas = {
    total: ConsultaCpf.where(consultado_em: periodo).count,
    sucesso: ConsultaCpf.where(consultado_em: periodo, status: "sucesso").count,
    falha: ConsultaCpf.where(consultado_em: periodo, status: "falha").count,
    por_origem: ConsultaCpf.where(consultado_em: periodo)
    .group(:origem).count,
    por_genero: ConsultaCpf.where(consultado_em: periodo, status: "sucesso")
    .group(:genero).count
    }

    taxa_sucesso = metricas[:total].positive? ?
    (metricas[:sucesso].to_f / metricas[:total] * 100).round(2) : 0

    metricas[:taxa_sucesso] = "#{taxa_sucesso}%"

    logger.info("[Relatorio] Metricas do periodo: #{metricas}")

    # Alerta se taxa de sucesso cair abaixo do esperado
    if taxa_sucesso < 90
    NotificacaoService.alertar(
    "Taxa de sucesso de consulta CPF abaixo de 90%: #{taxa_sucesso}%"
    )
    end
    end
end

Perguntas frequentes

Qual é a diferença entre Sidekiq-Cron e Rufus-Scheduler para jobs de CPF?

Sidekiq-Cron é integrado ao Sidekiq e ao Redis, gerencia filas com persistência e suporta retry automático — ideal para aplicações Rails em produção com alto volume. Rufus-Scheduler é um scheduler em processo, leve e sem dependência de Redis, mais adequado para scripts standalone ou aplicações de baixo volume. Para jobs críticos de CPF em produção, Sidekiq-Cron oferece maior resiliência.

Como evitar que o job de revalidação consuma todas as consultas do plano?

Defina um LIMITE_DIARIO no worker (o exemplo usa 500 CPFs/dia) e calcule o consumo mensal esperado. Com o plano Pro (1.000 consultas/mês), o limite diário de 33 CPFs já é suficiente para manter cadastros revalidados a cada 30 dias. Se o volume exceder o plano, a API não bloqueia: cobra R$0,15 por consulta adicional, o que é previsível e controlável.

Como implementar retry seguro sem reprocessar o mesmo CPF duas vezes?

Use o campo status como lock: antes de processar, mude para "processando". Ao concluir com sucesso, mude para "sucesso". Em caso de erro, reverta para "pendente" ou "falha". Assim, mesmo que o job seja reiniciado por um retry do Sidekiq, CPFs já processados não são consultados novamente.

Como monitorar se os jobs estão executando corretamente?

A Sidekiq Web UI exibe filas, jobs em execução e histórico de falhas em tempo real. Complementarmente, o RelatorioConsultasWorker gera métricas mensais e emite alerta se a taxa de sucesso cair abaixo de 90%. Para monitoramento externo, ferramentas como Healthchecks.io podem ser integradas ao final de cada job para confirmar execução bem-sucedida.


Conclusão

Um job scheduler em Ruby automatiza tarefas recorrentes de consulta e manutenção de CPF, garantindo que revalidações, processamento de pendências e limpezas ocorram de forma confiável e sem intervenção manual. Seja com Sidekiq-Cron para aplicações Rails ou Rufus-Scheduler para aplicações independentes, o agendamento de jobs é uma peça fundamental da infraestrutura de qualquer sistema que consome APIs de CPF em escala.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a automatizar suas consultas de CPF com a infraestrutura Ruby que você já usa.

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