"""Scheduled job for periodic MITRE ATT&CK synchronisation. Uses APScheduler's ``BackgroundScheduler`` to run :func:`sync_mitre` every 24 hours. The job manages its own database session (created on entry, closed in ``finally``) so it is fully independent from FastAPI's request-scoped sessions. """ import logging from apscheduler.schedulers.background import BackgroundScheduler from app.database import SessionLocal from app.services.mitre_sync_service import sync_mitre logger = logging.getLogger(__name__) # --------------------------------------------------------------------------- # Module-level scheduler instance # --------------------------------------------------------------------------- scheduler = BackgroundScheduler() def _run_mitre_sync() -> None: """Execute a MITRE sync inside its own DB session.""" logger.info("Scheduled MITRE sync job starting...") db = SessionLocal() try: summary = sync_mitre(db) logger.info("Scheduled MITRE sync job finished — %s", summary) except Exception: logger.exception("Scheduled MITRE sync job failed") finally: db.close() def start_scheduler() -> None: """Register the MITRE sync job and start the background scheduler. The job runs every **24 hours**. It does **not** fire immediately on startup — the first execution happens 24 h after the application boots. """ scheduler.add_job( _run_mitre_sync, trigger="interval", hours=24, id="mitre_sync", name="MITRE ATT&CK sync (every 24h)", replace_existing=True, ) scheduler.start() logger.info("MITRE sync scheduler started (interval=24h)")