2026-08-25 09:29:35 -05:00
|
|
|
"""main.py — entrada delgada. Bucle continuo dirigido por scheduler.json."""
|
|
|
|
|
import signal
|
2026-05-20 16:38:48 -05:00
|
|
|
import time
|
2026-08-25 09:29:35 -05:00
|
|
|
from datetime import datetime
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
from core import ejecutar
|
|
|
|
|
from scheduler import cargar_scheduler, franja_actual, proximo_inicio
|
|
|
|
|
from logger_manager import get_logger
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
logger = get_logger("main")
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
_running = True
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
# ============================================================================
|
|
|
|
|
def _signal_handler(signum, frame):
|
|
|
|
|
global _running
|
|
|
|
|
logger.info("⏹️ Señal de parada recibida. Deteniendo tras el ciclo actual...")
|
|
|
|
|
_running = False
|
2026-05-21 09:56:07 -05:00
|
|
|
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
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
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
# ============================================================================
|
2026-05-20 16:38:48 -05:00
|
|
|
if __name__ == "__main__":
|
2026-08-25 09:29:35 -05:00
|
|
|
signal.signal(signal.SIGINT, _signal_handler)
|
|
|
|
|
signal.signal(signal.SIGTERM, _signal_handler)
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
while _running:
|
|
|
|
|
try:
|
|
|
|
|
cfg_scheduler = cargar_scheduler()
|
|
|
|
|
ahora = datetime.now()
|
|
|
|
|
franja = franja_actual(cfg_scheduler, ahora)
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
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
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
ejecutar()
|
|
|
|
|
_dormir_interrumpible(franja["intervalo"])
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.error("Excepción no controlada en el ciclo", exc_info=True)
|
|
|
|
|
_dormir_interrumpible(60)
|
2026-05-20 16:38:48 -05:00
|
|
|
|
2026-08-25 09:29:35 -05:00
|
|
|
logger.info("👋 Proceso detenido.")
|
|
|
|
|
# ============================================================================
|