Refatoracao de qualidade de codigo

- Mover logica de routes.py para RankingMapper na camada de aplicacao
- Consolidar funcoes mesclar_periodos e anos_completos_periodos em periodo.py
- Extrair RankingCache para modulo separado em infrastructure/cache
- Substituir todos os print() por logging adequado
- Corrigir exception handlers genericos para tipos especificos
- Remover classe Atuacao e atributo atuacoes_raw nao utilizados
- Documentar status dos scripts utilitarios
This commit is contained in:
Frederico Castro
2025-12-14 21:47:00 -03:00
parent 4a98e8b38c
commit f91651056a
15 changed files with 284 additions and 218 deletions

View File

@@ -1,9 +1,12 @@
import logging
from datetime import datetime
from itertools import islice
from typing import Dict, List, Optional
from ...infrastructure.oracle.client import OracleClient
logger = logging.getLogger(__name__)
class PopularComponenteBJob:
"""
@@ -89,15 +92,15 @@ class PopularComponenteBJob:
Este método é síncrono; use asyncio.to_thread quando chamá-lo em corrotina.
"""
if not self.oracle_local.is_connected:
print("PopularComponenteB: Oracle LOCAL não conectado, abortando.")
logger.warning("PopularComponenteB: Oracle LOCAL não conectado, abortando.")
return
if not self.oracle_remote.is_connected:
print("PopularComponenteB: Oracle REMOTO não conectado, abortando.")
logger.warning("PopularComponenteB: Oracle REMOTO não conectado, abortando.")
return
ids_pessoas = self._buscar_ids_pendentes()
total_ids = len(ids_pessoas)
print(f"PopularComponenteB: {total_ids} consultores pendentes para COMPONENTE_B")
logger.info(f"PopularComponenteB: {total_ids} consultores pendentes para COMPONENTE_B")
processados = 0
com_ppg = 0
@@ -107,7 +110,7 @@ class PopularComponenteBJob:
try:
registros = self._buscar_ppg_lote(lote)
except Exception as e:
print(f"PopularComponenteB: erro ao buscar lote {lote[:3]}... -> {e}")
logger.warning(f"PopularComponenteB: erro ao buscar lote {lote[:3]}... -> {e}")
continue
por_pessoa: Dict[int, List[Dict]] = {}
@@ -127,14 +130,14 @@ class PopularComponenteBJob:
if len(batch) >= batch_updates:
self._aplicar_batch(batch)
print(f"PopularComponenteB: Processados {processados}/{total_ids} | Com PPG: {com_ppg}")
logger.info(f"PopularComponenteB: Processados {processados}/{total_ids} | Com PPG: {com_ppg}")
batch = []
if batch:
self._aplicar_batch(batch)
self._atualizar_posicoes()
print(f"PopularComponenteB: Finalizado. Processados={processados} Com PPG={com_ppg}")
logger.info(f"PopularComponenteB: Finalizado. Processados={processados} Com PPG={com_ppg}")
def _aplicar_batch(self, batch: List[Dict[str, int]]) -> None:
if not batch:

View File

@@ -1,8 +1,11 @@
import json
import logging
from datetime import datetime
from typing import Optional, Dict, Any
from ...infrastructure.elasticsearch.client import ElasticsearchClient
logger = logging.getLogger(__name__)
from ...infrastructure.oracle.client import OracleClient
from ...infrastructure.oracle.ranking_repository import RankingOracleRepository
from ...infrastructure.repositories.consultor_repository_impl import ConsultorRepositoryImpl
@@ -87,8 +90,8 @@ class ProcessarRankingJob:
except Exception as e:
import traceback
print(f"AVISO: Erro ao processar consultor {doc.get('id')}: {e}")
print(f"Traceback: {traceback.format_exc()}")
logger.warning(f"Erro ao processar consultor {doc.get('id')}: {e}")
logger.debug(f"Traceback: {traceback.format_exc()}")
continue
if consultores_para_inserir:

View File

@@ -1,10 +1,13 @@
import asyncio
import logging
from datetime import datetime, time, timedelta
from typing import Optional
from .processar_ranking import ProcessarRankingJob
from .popular_componente_b_job import PopularComponenteBJob
logger = logging.getLogger(__name__)
class RankingScheduler:
def __init__(self, job: ProcessarRankingJob, job_componente_b: PopularComponenteBJob | None = None):
@@ -24,7 +27,7 @@ class RankingScheduler:
proxima_execucao += timedelta(days=1)
segundos_ate_proxima = (proxima_execucao - agora).total_seconds()
print(f"Próxima execução do ranking: {proxima_execucao.strftime('%d/%m/%Y %H:%M:%S')}")
logger.info(f"Próxima execução do ranking: {proxima_execucao.strftime('%d/%m/%Y %H:%M:%S')}")
await asyncio.sleep(segundos_ate_proxima)
@@ -39,18 +42,18 @@ class RankingScheduler:
if not self.running:
break
print(f"[{datetime.now().strftime('%d/%m/%Y %H:%M:%S')}] Executando job de ranking automático")
logger.info("Executando job de ranking automático")
await self.job.executar(limpar_antes=True)
if self.job_componente_b:
print(f"[{datetime.now().strftime('%d/%m/%Y %H:%M:%S')}] Executando popular_componente_b após ranking")
logger.info("Executando popular_componente_b após ranking")
await asyncio.to_thread(self.job_componente_b.executar)
except asyncio.CancelledError:
print("Scheduler cancelado")
logger.info("Scheduler cancelado")
break
except Exception as e:
print(f"Erro no scheduler: {e}")
logger.error(f"Erro no scheduler: {e}")
await asyncio.sleep(3600)
async def iniciar(self, hora_alvo: int = 3) -> None:
@@ -64,7 +67,7 @@ class RankingScheduler:
self.running = True
self.task = asyncio.create_task(self._loop_diario(hora_alvo))
await asyncio.sleep(0.1)
print(f"Scheduler do ranking iniciado: job rodará diariamente às {hora_alvo}h")
logger.info(f"Scheduler do ranking iniciado: job rodará diariamente às {hora_alvo}h")
def parar(self) -> None:
"""