"""APScheduler task scheduler. T55: Background task scheduler using APScheduler with AsyncIOScheduler. """ from apscheduler.schedulers.asyncio import AsyncIOScheduler # Singleton scheduler instance _scheduler = None def get_scheduler(): """Get or create the singleton scheduler instance. Returns: AsyncIOScheduler: The scheduler instance (singleton) Example: >>> scheduler = get_scheduler() >>> scheduler.start() """ global _scheduler if _scheduler is None: _scheduler = AsyncIOScheduler(timezone='UTC') return _scheduler def scheduled_job(trigger, **trigger_args): """Decorator to register a scheduled job. Args: trigger: APScheduler trigger (IntervalTrigger, CronTrigger, etc.) **trigger_args: Additional arguments for add_job (id, name, etc.) Returns: Decorator function that registers the job and returns original function Example: >>> from apscheduler.triggers.interval import IntervalTrigger >>> >>> @scheduled_job(IntervalTrigger(hours=1), id='sync_task') ... async def sync_data(): ... pass """ def decorator(func): get_scheduler().add_job(func, trigger=trigger, **trigger_args) return func return decorator def init_scheduler(): """Initialize and start the scheduler. Should be called during application startup. Registers all decorated jobs and starts the scheduler. Example: >>> init_scheduler() >>> # Scheduler is now running """ scheduler = get_scheduler() scheduler.start() def shutdown_scheduler(): """Shutdown the scheduler gracefully. Should be called during application shutdown. Waits for running jobs to complete before stopping. Example: >>> shutdown_scheduler() >>> # Scheduler is stopped """ scheduler = get_scheduler() scheduler.shutdown(wait=True)