background_tasks.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. """
  2. 后台定时任务管理
  3. """
  4. import asyncio
  5. from typing import List, Optional
  6. from contextlib import asynccontextmanager
  7. from app.database import get_db
  8. from app.core.logger import logger
  9. from app.services.key_rotation_service import KeyRotationService
  10. from app.services.session_service import SessionService
  11. from app.services.heartbeat_monitor import HeartbeatMonitor
  12. from app.config import settings
  13. class BackgroundTaskManager:
  14. """后台任务管理器"""
  15. def __init__(self):
  16. self.tasks: List[asyncio.Task] = []
  17. self.running = False
  18. async def start_all_tasks(self):
  19. """启动所有后台任务"""
  20. if self.running:
  21. logger.warning("后台任务已在运行")
  22. return
  23. self.running = True
  24. logger.info("启动后台定时任务...")
  25. # 启动各个任务
  26. self.tasks = [
  27. asyncio.create_task(self._key_rotation_task()),
  28. asyncio.create_task(self._session_cleanup_task()),
  29. asyncio.create_task(self._heartbeat_cleanup_task()),
  30. ]
  31. logger.info(f"已启动 {len(self.tasks)} 个后台任务")
  32. async def stop_all_tasks(self):
  33. """停止所有后台任务"""
  34. if not self.running:
  35. logger.warning("后台任务未运行")
  36. return
  37. logger.info("停止后台定时任务...")
  38. self.running = False
  39. # 取消所有任务
  40. for task in self.tasks:
  41. if not task.done():
  42. task.cancel()
  43. # 等待任务完成
  44. try:
  45. await asyncio.gather(*self.tasks, return_exceptions=True)
  46. except asyncio.CancelledError:
  47. pass
  48. self.tasks.clear()
  49. logger.info("后台定时任务已停止")
  50. async def _key_rotation_task(self):
  51. """密钥轮换任务 - 每5分钟执行一次"""
  52. logger.info("启动密钥轮换定时任务 (间隔: 5分钟)")
  53. while self.running:
  54. try:
  55. logger.debug("执行密钥轮换检查...")
  56. db = next(get_db())
  57. try:
  58. # 检查是否需要轮换密钥
  59. if KeyRotationService.should_rotate_key(db):
  60. logger.info("检测到需要轮换密钥,开始执行...")
  61. success, public_key, error_msg = KeyRotationService.rotate_key(db)
  62. if success:
  63. logger.info("密钥轮换成功")
  64. else:
  65. logger.error(f"密钥轮换失败: {error_msg}")
  66. else:
  67. logger.debug("当前无需轮换密钥")
  68. # 清理过期密钥
  69. cleaned_count = KeyRotationService.cleanup_expired_keys(db)
  70. if cleaned_count > 0:
  71. logger.info(f"清理了 {cleaned_count} 个过期密钥")
  72. finally:
  73. db.close()
  74. except Exception as e:
  75. logger.exception("密钥轮换任务异常")
  76. # 等待5分钟
  77. await asyncio.sleep(300) # 5分钟 = 300秒
  78. async def _session_cleanup_task(self):
  79. """Session清理任务 - 每2小时执行一次"""
  80. logger.info("启动Session清理定时任务 (间隔: 2小时)")
  81. while self.running:
  82. try:
  83. logger.debug("执行Session清理...")
  84. db = next(get_db())
  85. try:
  86. cleaned_count = SessionService.cleanup_expired_sessions(db)
  87. if cleaned_count > 0:
  88. logger.info(f"清理了 {cleaned_count} 个30天前的非活跃Session记录")
  89. else:
  90. logger.debug("没有需要清理的旧Session记录")
  91. finally:
  92. db.close()
  93. except Exception as e:
  94. logger.exception("Session清理任务异常")
  95. # 等待2小时
  96. await asyncio.sleep(7200) # 2小时 = 7200秒
  97. async def _heartbeat_cleanup_task(self):
  98. """心跳监控缓存清理任务 - 每1小时执行一次"""
  99. logger.info("启动心跳缓存清理定时任务 (间隔: 1小时)")
  100. while self.running:
  101. try:
  102. logger.debug("执行心跳缓存清理...")
  103. cleaned_count = HeartbeatMonitor.cleanup_cache()
  104. if cleaned_count > 0:
  105. logger.info(f"清理了 {cleaned_count} 个过期的缓存条目")
  106. else:
  107. logger.debug("心跳缓存状态正常,无需清理")
  108. # 输出监控统计信息
  109. stats = HeartbeatMonitor.get_monitoring_stats()
  110. logger.info(f"心跳监控统计: 监控用户={stats.get('total_monitored_users', 0)}, "
  111. f"受保护用户={stats.get('protected_users', 0)}, "
  112. f"失败用户={stats.get('failing_users', 0)}, "
  113. f"缓存大小={stats.get('cache_size', 0)}")
  114. except Exception as e:
  115. logger.exception("心跳缓存清理任务异常")
  116. # 等待1小时
  117. await asyncio.sleep(3600) # 1小时 = 3600秒
  118. # 全局后台任务管理器实例
  119. background_task_manager = BackgroundTaskManager()
  120. @asynccontextmanager
  121. async def lifespan_manager(app):
  122. """FastAPI lifespan 事件管理器"""
  123. # 启动时执行
  124. logger.info("应用启动,开始初始化后台任务...")
  125. await background_task_manager.start_all_tasks()
  126. yield
  127. # 关闭时执行
  128. logger.info("应用关闭,开始清理后台任务...")
  129. await background_task_manager.stop_all_tasks()
  130. # 便捷函数
  131. async def start_background_tasks():
  132. """启动后台任务(手动调用)"""
  133. await background_task_manager.start_all_tasks()
  134. async def stop_background_tasks():
  135. """停止后台任务(手动调用)"""
  136. await background_task_manager.stop_all_tasks()
  137. def get_task_manager() -> BackgroundTaskManager:
  138. """获取后台任务管理器实例"""
  139. return background_task_manager