"""main.py — entrada delgada. Bucle continuo dirigido por scheduler.json.""" import signal import time from datetime import datetime from core import ejecutar from scheduler import cargar_scheduler, franja_actual, proximo_inicio from logger_manager import get_logger logger = get_logger("main") _running = True # ============================================================================ def _signal_handler(signum, frame): global _running logger.info("⏹️ Señal de parada recibida. Deteniendo tras el ciclo actual...") _running = False def _dormir_interrumpible(segundos: float): """Duerme en pasos de 1s para reaccionar rápido a SIGTERM/SIGINT.""" restante = int(segundos) while restante > 0 and _running: time.sleep(min(1, restante)) restante -= 1 # ============================================================================ if __name__ == "__main__": signal.signal(signal.SIGINT, _signal_handler) signal.signal(signal.SIGTERM, _signal_handler) while _running: try: cfg_scheduler = cargar_scheduler() ahora = datetime.now() franja = franja_actual(cfg_scheduler, ahora) if franja is None: proximo = proximo_inicio(cfg_scheduler, ahora) segundos = max((proximo - ahora).total_seconds(), 0) logger.info( f"⏸️ Fuera de horario. Próxima franja: {proximo:%Y-%m-%d %H:%M} " f"(durmiendo {int(segundos)}s)" ) _dormir_interrumpible(segundos) continue ejecutar() _dormir_interrumpible(franja["intervalo"]) except Exception: logger.error("Excepción no controlada en el ciclo", exc_info=True) _dormir_interrumpible(60) logger.info("👋 Proceso detenido.") # ============================================================================