64 lines
1.6 KiB
Python
64 lines
1.6 KiB
Python
#!/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())
|
|
|
|
|