diff --git a/src/schedule/database.py b/src/schedule/database.py index ee771ac53..72c017c82 100644 --- a/src/schedule/database.py +++ b/src/schedule/database.py @@ -293,3 +293,37 @@ async def has_active_plans(month: str) -> bool: except Exception as e: logger.error(f"检查 {month} 的有效月度计划时发生错误: {e}") return False + + +async def delete_plans_older_than(month: str): + """ + 删除指定月份之前的所有月度计划。 + + :param month: 目标月份,格式为 "YYYY-MM"。早于此月份的计划都将被删除。 + """ + async with get_db_session() as session: + try: + # 首先,查询要删除的计划,用于日志记录 + result = await session.execute(select(MonthlyPlan).where(MonthlyPlan.target_month < month)) + plans_to_delete = result.scalars().all() + + if not plans_to_delete: + logger.info(f"没有找到比 {month} 更早的月度计划需要删除。") + return 0 + + plan_months = sorted(list(set(p.target_month for p in plans_to_delete))) + logger.info(f"将删除 {len(plans_to_delete)} 条早于 {month} 的月度计划 (涉及月份: {', '.join(plan_months)})。") + + # 然后,执行删除操作 + delete_stmt = delete(MonthlyPlan).where(MonthlyPlan.target_month < month) + delete_result = await session.execute(delete_stmt) + deleted_count = delete_result.rowcount + await session.commit() + + logger.info(f"成功删除了 {deleted_count} 条旧的月度计划。") + return deleted_count + + except Exception as e: + logger.error(f"删除早于 {month} 的月度计划时发生错误: {e}") + await session.rollback() + raise diff --git a/src/schedule/monthly_plan_manager.py b/src/schedule/monthly_plan_manager.py index 3e6eb6503..1893cbc91 100644 --- a/src/schedule/monthly_plan_manager.py +++ b/src/schedule/monthly_plan_manager.py @@ -1,9 +1,12 @@ import asyncio from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta + from src.common.logger import get_logger from src.manager.async_task_manager import AsyncTask, async_task_manager +from . import database from .plan_manager import PlanManager logger = get_logger("monthly_plan_manager") @@ -28,6 +31,13 @@ class MonthlyPlanManager: 会启动一个每月的后台任务来自动生成计划。 """ logger.info("正在初始化月度计划管理器...") + + # 在启动时清理两个月前的旧计划 + two_months_ago = datetime.now() - relativedelta(months=2) + cleanup_month_str = two_months_ago.strftime("%Y-%m") + logger.info(f"执行启动时月度计划清理任务,将删除 {cleanup_month_str} 之前的计划...") + await database.delete_plans_older_than(cleanup_month_str) + await self.start_monthly_plan_generation() logger.info("月度计划管理器初始化成功") @@ -90,7 +100,7 @@ class MonthlyPlanGenerationTask(AsyncTask): next_month = datetime(now.year + 1, 1, 1) else: next_month = datetime(now.year, now.month + 1, 1) - + sleep_seconds = (next_month - now).total_seconds() logger.info( f" 下一次月度计划生成任务将在 {sleep_seconds:.2f} 秒后运行 (北京时间 {next_month.strftime('%Y-%m-%d %H:%M:%S')})" @@ -100,7 +110,7 @@ class MonthlyPlanGenerationTask(AsyncTask): # 到达月初,先归档上个月的计划 last_month = (next_month - timedelta(days=1)).strftime("%Y-%m") await self.monthly_plan_manager.plan_manager.archive_current_month_plans(last_month) - + # 为当前月生成新计划 current_month = next_month.strftime("%Y-%m") logger.info(f" 到达月初,开始生成 {current_month} 的月度计划...")