from fastapi import FastAPI from app.core.constants import ActorValue from app.core.config import get_settings from app.modules.feishu.constants import FeishuReceiveIdType def attach_scheduler(app: FastAPI) -> None: """Attach optional APScheduler jobs to the FastAPI application.""" settings = get_settings() if not settings.scheduler_enabled: return from apscheduler.schedulers.background import BackgroundScheduler from app.core.database import SessionLocal from app.core.task_queue import ( enqueue_daily_brief_push, enqueue_legacy_project_sync, enqueue_legacy_task_sync, enqueue_project_weekly_push, ) from app.modules.reports.service import ReportService scheduler = BackgroundScheduler(timezone="Asia/Shanghai") def run_daily_brief() -> None: db = SessionLocal() try: report = ReportService(db).daily_brief() app.state.last_daily_brief = report if ( settings.feishu_app_id and settings.feishu_app_secret and settings.feishu_default_chat_id ): if settings.task_queue_enabled: app.state.last_daily_brief_dispatch = enqueue_daily_brief_push( receive_id=settings.feishu_default_chat_id, receive_id_type=FeishuReceiveIdType.CHAT_ID, actor=ActorValue.SCHEDULER, ) return ReportService(db).push_report( report, receive_id=settings.feishu_default_chat_id, receive_id_type=FeishuReceiveIdType.CHAT_ID, actor=ActorValue.SCHEDULER, ) finally: db.close() def run_project_weekly() -> None: db = SessionLocal() try: report = ReportService(db).project_weekly() app.state.last_project_weekly = report if ( settings.feishu_app_id and settings.feishu_app_secret and settings.feishu_default_chat_id ): if settings.task_queue_enabled: app.state.last_project_weekly_dispatch = enqueue_project_weekly_push( receive_id=settings.feishu_default_chat_id, receive_id_type=FeishuReceiveIdType.CHAT_ID, actor=ActorValue.SCHEDULER, ) return ReportService(db).push_report( report, receive_id=settings.feishu_default_chat_id, receive_id_type=FeishuReceiveIdType.CHAT_ID, actor=ActorValue.SCHEDULER, ) finally: db.close() def run_legacy_project_sync() -> None: app.state.last_legacy_project_sync_dispatch = enqueue_legacy_project_sync( actor=ActorValue.SCHEDULER, ) def run_legacy_task_sync() -> None: app.state.last_legacy_task_sync_dispatch = enqueue_legacy_task_sync( actor=ActorValue.SCHEDULER, ) scheduler.add_job( run_daily_brief, trigger="cron", hour=settings.daily_brief_cron_hour, minute=settings.daily_brief_cron_minute, id="daily_brief_push", replace_existing=True, ) scheduler.add_job( run_project_weekly, trigger="cron", day_of_week=settings.weekly_project_report_day_of_week, hour=settings.weekly_project_report_cron_hour, minute=settings.weekly_project_report_cron_minute, id="project_weekly_push", replace_existing=True, ) if settings.legacy_sync_enabled and settings.legacy_project_query: scheduler.add_job( run_legacy_project_sync, trigger="cron", hour=settings.legacy_project_sync_cron_hour, minute=settings.legacy_project_sync_cron_minute, id="legacy_project_sync", replace_existing=True, ) if settings.legacy_sync_enabled and settings.legacy_task_query: scheduler.add_job( run_legacy_task_sync, trigger="cron", hour=settings.legacy_task_sync_cron_hour, minute=settings.legacy_task_sync_cron_minute, id="legacy_task_sync", replace_existing=True, ) @app.on_event("startup") def start_scheduler() -> None: scheduler.start() @app.on_event("shutdown") def stop_scheduler() -> None: scheduler.shutdown(wait=False)