bootstrap.py 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. """应用生命周期管理 —— 回调注册模式"""
  2. import asyncio
  3. import logging
  4. from typing import Callable, Awaitable, List
  5. logger = logging.getLogger(__name__)
  6. StartupCallback = Callable[[], Awaitable[None]]
  7. ShutdownCallback = Callable[[], Awaitable[None]]
  8. class AppContext:
  9. """管理应用启动/关闭生命周期
  10. 使用方式:
  11. ctx = AppContext()
  12. ctx.on_startup(db.init_pools)
  13. ctx.on_startup(log_service.start)
  14. ctx.on_shutdown(db.close_pools)
  15. ctx.on_shutdown(log_service.stop)
  16. # 在 Quart/FastAPI 生命周期中调用
  17. await ctx.start_up()
  18. await ctx.shutdown()
  19. """
  20. def __init__(self):
  21. self._startup_callbacks: List[StartupCallback] = []
  22. self._shutdown_callbacks: List[ShutdownCallback] = []
  23. def on_startup(self, callback: StartupCallback) -> "AppContext":
  24. """注册启动回调(支持链式调用)"""
  25. self._startup_callbacks.append(callback)
  26. return self
  27. def on_shutdown(self, callback: ShutdownCallback) -> "AppContext":
  28. """注册关闭回调(支持链式调用)"""
  29. self._shutdown_callbacks.append(callback)
  30. return self
  31. async def start_up(self) -> None:
  32. """按注册顺序执行所有启动回调"""
  33. logger.info("应用启动中...")
  34. results = await asyncio.gather(
  35. *(cb() for cb in self._startup_callbacks),
  36. return_exceptions=True,
  37. )
  38. for i, result in enumerate(results):
  39. if isinstance(result, Exception):
  40. logger.error(f"启动回调 [{i}] 失败: {result}")
  41. logger.info("应用启动完成")
  42. async def shutdown(self) -> None:
  43. """按注册逆序执行所有关闭回调"""
  44. logger.info("应用关闭中...")
  45. for callback in reversed(self._shutdown_callbacks):
  46. try:
  47. await callback()
  48. except Exception as e:
  49. logger.error(f"关闭回调失败: {e}")
  50. logger.info("应用已关闭")