Skip to content

PAV-178: [Jobs Processor] Otimizar agendamento e distribuição de carga dos providers - #332

Merged
hltav merged 18 commits into
Cla-Code-Community:developfrom
hltav:hltavdev/pav-178-jobs-processor-otimizar-agendamento-e-distribuicao-de-carga
Nov 2, 2026
Merged

hltav merged 18 commits into
Cla-Code-Community:developfrom
hltav:hltavdev/pav-178-jobs-processor-otimizar-agendamento-e-distribuicao-de-carga

Conversation

@hltav

@hltav hltav commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Descricao

Distribui os oito providers em 21 janelas automáticas diárias, com seleção efetiva por ProviderID e coordenação pelo lock global existente. Implementa grupos fixos Greenhouse, deadline absoluto, cobertura de keywords LinkedIn/Adzuna e orçamentos operacionais Gupy/Jooble. Preserva resultados parciais no catálogo PostgreSQL e na projeção Valkey, com status operacional compatível com falhas e timeouts. A integração foi validada com serviços descartáveis; a ativação automática em DEV permanece condicionada à configuração e à validação operacional.

Linear

PAV-178

Close PAV-178

Como foi testado

Resultados comprovados nas rodadas anteriores:

Validação Resultado
Testes Go direcionados 475 aprovados
Testes Go com detector de corridas 414 aprovados
Integração Go com PostgreSQL e Valkey descartáveis 15 aprovados
Testes backend direcionados 56 aprovados
Testes backend com Valkey real descartável 18 aprovados
Build Go e verificação TypeScript Aprovados
Hotfix final: cronjob e runlock com -race Aprovados

Esses números representam execuções distintas e não devem ser somados como casos únicos.

Na preparação deste PR, os comandos npm test de backend e frontend foram tentados conforme a skill. Ambos terminaram antes de executar casos, com código 127 e vitest: not found, pois esta worktree está sem dependências locais. Não foram instaladas dependências nem repetidas as integrações anteriores.

Reprodução direcionada

Com dependências instaladas e sem apontar configurações de teste para serviços compartilhados:

cd scraper-go
go test ./internal/config ./internal/cronjob ./internal/runlock ./internal/pipeline ./internal/adapters/... -count=1 -timeout=60s
go test -race ./internal/cronjob ./internal/runlock -count=1 -timeout=40s

Para as integrações, configurar PAV125_TEST_DATABASE_URL e PAV125_TEST_VALKEY_URL exclusivamente para instâncias descartáveis dedicadas:

cd scraper-go
go test ./internal/catalogops ./internal/pipeline -count=1 -timeout=120s

A integração backend de busca versionada utiliza:

cd backend
npx --no-install vitest run tests/integration/jobs.valkey.test.ts
npx --no-install tsc --noEmit -p tsconfig.json

Não executar seeds ou scrapers reais como parte desses testes.

Objetivo

Reduzir concentração de carga entre providers e distribuir a atualização do catálogo ao longo do dia, preservando os controles existentes de concorrência, persistência e coordenação.

A grade é a configuração operacional acordada. A caracterização completa de duração, CPU, memória e volume dos oito providers ainda deverá ser medida em DEV; este PR não apresenta essa capacidade como comprovada.

Resumo das alterações

Etapa Entrega
P0 — bf554a5 Preset com 21 janelas, timezone local, identidade independente e deduplicação das ocorrências.
P1 — 284d1c9 Manifesto versionado com quatro grupos fixos Greenhouse.
P2 — 85793e5 Deadline absoluto, reservas para finalização, admissão pontual e coordenação persistente.
P3 — 814026a Cobertura das keywords elegíveis LinkedIn/Adzuna por janela, preservando modos legados.
P3.1 — 9fad872 Orçamentos e cursor Gupy, preservação parcial e reserva atômica da cota Jooble.
P4 — 95e4e34 Testes finais de cobertura/integração e correção da admissão tardia causada pela latência do Valkey.

A branch também inclui os commits anteriores da PAV-178: seleção por ProviderID, controle de ativação, preservação parcial, bloqueio de seeds demonstrativos, otimizações e observabilidade do pipeline.

Arquivos e módulos afetados

  • Configuração: scraper-go/internal/config/, incluindo provider_schedule.go.
  • Scheduler: scraper-go/internal/cronjob/, incluindo despacho, manifesto Greenhouse, cursor Gupy e Retry-After.
  • Coordenação: scraper-go/internal/runlock/.
  • Pipeline e dados: pipeline/, catalog/, catalogops/, jobstore/, jobindex/, classifier/ e metrics/.
  • Providers: adapters e respectivos testes de cobertura, orçamento e resultados parciais.
  • Servidor Go: contratos administrativos em scraper-go/cmd/server/.
  • Backend: integração administrativa Node → Go, tipos operacionais, proteção de seeds e testes.
  • Docker: docker/docker-compose.app.yml e docker/docker-compose.migrate.yml.
  • Documentação commitada: docs/PAV-178-dev.md, docs/PAV-178-PR.md e documentação técnica do Processor.

Nenhuma alteração da PAV-181 integra este PR.

Arquitetura e funcionamento do scheduler

O preset SCRAPER_PROVIDER_WINDOWS=pav178 reutiliza o scheduler e o lock distribuído existentes. A configuração de janelas substitui o acionamento periódico legado nesse modo.

Todos os horários abaixo são locais em America/Sao_Paulo:

Provider Janelas
Greenhouse 00h, 06h, 11h, 17h
Gupy 01h, 07h, 12h, 18h
InHire 02h, 08h, 13h, 19h
LinkedIn 03h, 09h, 16h
Adzuna 04h, 14h
Lever 05h, 15h
The Muse 10h
Jooble 20h

São 21 ocorrências diárias, com IDs estáveis e claims persistidos por data local.

  • Admissão limitada à tolerância de 30 segundos após o horário previsto.
  • Revalidação temporal após a coordenação no Valkey, enquanto o lease global está adquirido.
  • Admissão tardia registrada como missed:admission_late, sem executar o provider.
  • Ocorrências impedidas não geram backlog, catch-up ou compensação em outro horário.
  • Execução limitada a 55 minutos totais, com reservas internas para processamento e liberação.
  • Conclusão antecipada aguarda a próxima janela; não encadeia outro provider.
  • Pausa global persistente de cinco minutos também protege disparos manuais.
  • Claims, checkpoints e coordenação dependem da retenção do Valkey.

Cobertura dos providers

  • Greenhouse: manifesto com 3.339 identidades estáveis, distribuídas em 850/850/850/789. Falhas e timeouts não redistribuem empresas entre janelas. Alterações do catálogo exigem revisão explícita do manifesto.
  • Gupy: até 120 queries por janela automática, cinco páginas por query e 600 tentativas HTTP, incluindo retries. Coleta sequencial, detecção de páginas repetidas, cursor persistente e preservação parcial.
  • LinkedIn/Adzuna: conjunto configurado de keywords elegíveis por ocorrência; limites de paginação, taxa e deadline continuam aplicáveis.
  • InHire: catálogo de 496 tenants.
  • Lever: catálogo de 44 empresas em ambas as janelas.
  • The Muse: limite padrão de 50 páginas, com preservação dos resultados parciais.
  • Jooble: uma janela diária às 20h, até 37 keywords, cursor e cadência existentes; teto compartilhado de até 150 tentativas HTTP/dia, reservado atomicamente antes do envio.

Cobertura planejada não significa conclusão garantida quando a fonte limita requisições ou o deadline é atingido.

Validações realizadas

Foram cobertos seleção exclusiva, horários locais, deduplicação após reinício, sobreposição, timeout, cancelamento, resultados parciais, persistência/indexação, quotas e cobertura dos catálogos.

Os testes finais do hotfix simulam a latência da coordenação sem sleeps longos e confirmam:

  • admissão dentro da tolerância;
  • rejeição depois da tolerância;
  • ausência de execução do provider rejeitado;
  • liberação do lock e dos recursos de execução;
  • ocorrência perdida consumida após reinício;
  • próxima janela elegível;
  • preservação da pausa global.

A comparação com upstream/develop não apresentou conflitos textuais na simulação de merge. Os testes anteriores foram executados na branch PAV-178, não sobre uma integração com os 34 commits posteriores do destino.

Impacto de banco e migrations

Não há nova migration neste PR.

O catálogo PostgreSQL, IDs estáveis, transações e revisões de indexação existentes são preservados. Falhas de indexação deixam pendências identificáveis por indexed_revision < revision, recuperáveis pelos mecanismos existentes.

O deploy deixa de executar automaticamente o seed demonstrativo. Migrations e backfill legítimo de PII continuam no fluxo.

O startup exige o catálogo migrado e recusa estados que demandem backfill/reconstrução explícita. Não há limpeza ou reconstrução automática de índices.

Impacto de configuração e variáveis de ambiente

A origem das configurações do scraper é o .env global da raiz do repositório, não o .env do backend.

O Compose principal inclui os arquivos modulares com project_directory: .. O serviço scraper-go:

  • recebe ./.env por env_file;
  • monta esse arquivo em /app/.env como somente leitura;
  • recebe valores explícitos em environment, que prevalecem sobre env_file;
  • recebe DATABASE_URL pelo módulo de migrations e VALKEY_URL pela configuração do serviço.

O carregamento Go utiliza godotenv.Load, sem sobrescrever variáveis já presentes no processo.

Variável Configuração/efeito
SCRAPER_SCHEDULER_ENABLED Manter false em DEV até ativação controlada. O padrão do código é true.
SCRAPER_PROVIDER_WINDOWS pav178 seleciona a grade. Vazio mantém o modo legado quando habilitado.
SCRAPER_SCHEDULE_TIMEZONE O preset utiliza America/Sao_Paulo; rejeita timezone incompatível.
SCRAPER_SCRAPE_TIMEOUT Padrão 50m; coleta limitada também pelo deadline total e reservas de finalização.
GUPY_AUTO_QUERY_LIMIT Padrão 120, exclusivo do modo automático correspondente.
GUPY_AUTO_MAX_PAGES Padrão 5.
GUPY_AUTO_MAX_HTTP_ATTEMPTS Padrão 600, incluindo retries.
JOOBLE_DAILY_HTTP_LIMIT Padrão 150; aceita valores entre 1 e 150.
SCRAPER_GREENHOUSE_BATCH_SIZE Mantido para o fluxo legado/manual; não substitui os grupos fixos do preset.

SCRAPER_SCHEDULER_ENABLED, os três limites automáticos Gupy e JOOBLE_DAILY_HTTP_LIMIT chegam pelo env_file, sem override explícito nesses campos do Compose. Timeout, janelas, concorrência, batches e parâmetros do lock possuem entradas explícitas em environment.

Flags, credenciais e catálogos

Provider Requisitos
LinkedIn Registrado sem flag ou credencial obrigatória nesse registry.
Adzuna ADZUNA_APP_ID e ADZUNA_APP_KEY.
Gupy GUPY_ENABLED=true; preservar as flags de discovery/sweep existentes.
InHire INHIRE_ENABLED=true; catálogo indicado por INHIRE_TENANTS_FILE.
Greenhouse GREENHOUSE_ENABLED=true; catálogo indicado por GREENHOUSE_COMPANIES_FILE, compatível com o manifesto.
Lever LEVER_ENABLED=true; catálogo indicado por LEVER_COMPANIES_FILE. O padrão do Compose é false.
The Muse Registrado sem flag; THEMUSE_API_KEY é opcional no adapter.
Jooble JOOBLE_API_KEY e Valkey disponível para controle de quota.

Com SCRAPER_PROVIDER_WINDOWS=pav178, os oito providers precisam estar disponíveis no registry mesmo com o scheduler desabilitado, pois a validação ocorre no startup.

Também permanecem necessários PostgreSQL/Valkey, configurações de concorrência e parâmetros de lease existentes. Nenhuma credencial ou arquivo .env está incluído neste PR.

Impacto de contratos e APIs

Preserva o disparo sem seleção explícita e adiciona seleção administrativa por provider, com validação e encaminhamento Node → Go.

O status administrativo expõe resumo da última execução e janelas configuradas. Timeout com vagas persistidas é distinguido de sucesso completo.

A integração mantém tratamento de seleção inválida, conflito de execução, rate limit/Retry-After e indisponibilidade de coordenação.

A busca backend utiliza a versão ativa em scraper:jobs:index-version e documentos em scraper:jobs:ns:<versao>:job:<id>. Índices legados com IDs sem documentos não recuperam conteúdo perdido.

Segurança e privacidade

Mantém autenticação e autorização administrativas existentes no backend. Os endpoints administrativos Go devem permanecer acessíveis pela rede interna prevista.

Não inclui credenciais, .env, binários ou Compose temporário. Não executa seeds, coletas reais, reconstruções de índice ou alterações em produção.

As integrações utilizaram dados e serviços descartáveis.

Riscos e limitações

  • Pré-condição de DEV: confirmar migrations, disponibilidade do catálogo e versão ativa do índice. Estado legado inconsistente pode impedir o startup.
  • Pré-condição do preset: habilitar os providers exigidos e provisionar suas credenciais; Lever vem desabilitado por padrão.
  • Validação pendente: repetir CI após a integração com o develop atualizado.
  • Medição pendente: duração, recursos e cobertura real dos oito providers em DEV. Quotas operacionais não comprovam limites contratuais das fontes.
  • Documentação pendente: parte dos documentos commitados ainda descreve o fluxo legado. O handoff docs/PAV-178-scheduler-automatico.md permanece não rastreado e não integra este PR.
  • Mudanças no catálogo Greenhouse e na lista de queries Gupy exigem tratamento explícito de manifesto/cursor.
  • Histórico detalhado em memória não constitui histórico SQL durável.
  • Deadline e shutdown dependem da cooperação dos adapters com o cancelamento. Encerramento abrupto do processo pode perder resultados ainda em memória.
  • Os testes completos backend/frontend não foram reexecutados nesta preparação por ausência de dependências locais.

Rollback

Manter ou retornar SCRAPER_SCHEDULER_ENABLED=false e utilizar a imagem anterior aprovada em DEV, sem apagar catálogo, índices, checkpoints ou volumes.

Verificar a compatibilidade dos estados persistidos antes de voltar a um scheduler legado. Não remover claims ou contornar locks para recuperar ocorrências perdidas.

Rollback de namespace do índice, quando necessário, exige procedimento separado e validação dos documentos existentes.

Fora do escopo

Deploy, ativação automática, merge, mudanças da PAV-181, reconstrução de índices em produção, remoção de dados demonstrativos já existentes e novas migrations.

Também ficam fora do escopo novas políticas de frequência, aumento de concorrência e um dashboard/histórico completo de execuções — relacionado à PAV-179.

Checklist final

  • P0, P1, P2, P3, P3.1 e P4 registradas na branch.
  • Lock global, concorrência e resultados parciais preservados nos testes.
  • Hotfix de admissão tardia validado com -race.
  • Integrações PostgreSQL/Valkey descartáveis aprovadas nas rodadas anteriores.
  • Comparação atualizada e simulação sem conflitos.
  • Sem alterações de frontend/PAV-181 ou arquivos locais excluídos do escopo.
  • Executar CI e regressões sobre a integração com develop atualizado.
  • Atualizar documentação operacional legada antes da ativação automática.
  • Confirmar flags, credenciais, catálogo e índice no destino DEV.
  • Publicar inicialmente com scheduler desabilitado.
  • Medir os oito providers e validar capacidade antes da ativação controlada.

@hltav
hltav merged commit 9c41b4f into Cla-Code-Community:develop Nov 2, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in JobAtlas – Kanban Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants