feat: Implementa job de ranking para 300k consultores
Backend: - Adiciona Scroll API no cliente Elasticsearch para processar todos os 300k+ consultores - Cria tabela TB_RANKING_CONSULTOR no Oracle para ranking pré-calculado - Implementa job de processamento com APScheduler (diário às 3h) - Adiciona endpoints: /ranking/paginado, /ranking/status, /ranking/processar, /ranking/estatisticas - Repository Oracle com paginação eficiente via ROW_NUMBER - Status do job com progresso em tempo real (polling) - Leitura automática de LOBs no OracleClient Frontend: - Componente RankingPaginado com paginação completa - Barra de progresso do job em tempo real - Botão para reprocessar ranking - Alternância entre Top N (rápido) e Ranking Completo (300k) Infraestrutura: - Docker compose com depends_on para garantir Oracle disponível - Schema SQL com procedure SP_ATUALIZAR_POSICOES - Índices otimizados para paginação
This commit is contained in:
50
backend/src/application/jobs/scheduler.py
Normal file
50
backend/src/application/jobs/scheduler.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from typing import Optional
|
||||
|
||||
from .processar_ranking import ProcessarRankingJob
|
||||
|
||||
|
||||
class RankingScheduler:
|
||||
def __init__(self, job: ProcessarRankingJob):
|
||||
self.job = job
|
||||
self.scheduler: Optional[AsyncIOScheduler] = None
|
||||
|
||||
def iniciar(self) -> None:
|
||||
"""
|
||||
Inicia o scheduler e agenda o job para rodar diariamente às 3h.
|
||||
"""
|
||||
if self.scheduler and self.scheduler.running:
|
||||
return
|
||||
|
||||
self.scheduler = AsyncIOScheduler()
|
||||
|
||||
self.scheduler.add_job(
|
||||
self.job.executar,
|
||||
trigger=CronTrigger(hour=3, minute=0),
|
||||
id='ranking_diario',
|
||||
name='Processamento diário do ranking de consultores',
|
||||
replace_existing=True,
|
||||
kwargs={"limpar_antes": True}
|
||||
)
|
||||
|
||||
self.scheduler.start()
|
||||
|
||||
def parar(self) -> None:
|
||||
"""
|
||||
Para o scheduler.
|
||||
"""
|
||||
if self.scheduler and self.scheduler.running:
|
||||
self.scheduler.shutdown(wait=False)
|
||||
|
||||
def executar_agora(self) -> None:
|
||||
"""
|
||||
Executa o job imediatamente (fora do agendamento).
|
||||
"""
|
||||
if self.scheduler:
|
||||
self.scheduler.add_job(
|
||||
self.job.executar,
|
||||
id='ranking_manual',
|
||||
replace_existing=True,
|
||||
kwargs={"limpar_antes": True}
|
||||
)
|
||||
Reference in New Issue
Block a user