from typing import Callable, Dict, Any from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.interval import IntervalTrigger import logging from app.services.service_registry import ServiceRegistry logger = logging.getLogger(__name__) class BaseScheduler: def __init__(self): self.scheduler = AsyncIOScheduler() self.jobs: Dict[str, Any] = {} ServiceRegistry.register(self.__class__.__name__, self) async def schedule_task( self, task_name: str, func: Callable, interval_seconds: int, *args, **kwargs ) -> None: """Schedule a task to run at regular intervals using APScheduler""" if task_name in self.jobs: logger.warning(f"Task {task_name} already exists. Removing existing job.") self.jobs[task_name].remove() job = self.scheduler.add_job( func, trigger=IntervalTrigger(seconds=interval_seconds), args=args, kwargs=kwargs, id=task_name, replace_existing=True ) self.jobs[task_name] = job logger.info(f"Scheduled task {task_name} to run every {interval_seconds} seconds") def remove_task(self, task_name: str) -> None: """Remove a scheduled task""" if task_name in self.jobs: self.jobs[task_name].remove() del self.jobs[task_name] logger.info(f"Removed task {task_name}") def start(self) -> None: """Start the scheduler""" self.scheduler.start() logger.info("Scheduler started") async def shutdown(self) -> None: """Shutdown the scheduler""" try: self.scheduler.shutdown() logger.info("Scheduler stopped") except AttributeError as e: if "'NoneType' object has no attribute 'call_soon_threadsafe'" in str(e): logger.warning("Event loop already closed, skipping scheduler shutdown") else: raise