#!/usr/bin/env python3 """ Standalone scheduler runner for Pounce. Runs APScheduler jobs without starting the FastAPI server. Recommended for production to avoid duplicate jobs when running multiple API workers. """ import asyncio import logging import signal from dotenv import load_dotenv # Load .env early (same as app/main.py) load_dotenv() from app.config import get_settings from app.database import init_db from app.scheduler import start_scheduler, stop_scheduler logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", ) logger = logging.getLogger("pounce.scheduler") async def main() -> None: settings = get_settings() logger.info("Starting scheduler runner for %s...", settings.app_name) # Ensure DB schema exists (create_all for new installs) await init_db() logger.info("Database initialized") start_scheduler() logger.info("Scheduler started") stop_event = asyncio.Event() def _request_shutdown(sig: signal.Signals) -> None: logger.info("Received %s, shutting down scheduler...", sig.name) stop_event.set() loop = asyncio.get_running_loop() for sig in (signal.SIGTERM, signal.SIGINT): try: loop.add_signal_handler(sig, lambda s=sig: _request_shutdown(s)) except NotImplementedError: # Fallback (Windows / limited environments) signal.signal(sig, lambda *_: _request_shutdown(sig)) await stop_event.wait() stop_scheduler() logger.info("Scheduler stopped. Bye.") if __name__ == "__main__": asyncio.run(main())