This commit is contained in:
2025-11-20 11:42:18 +08:00
parent 1bd91df9a1
commit e2d2b0b75b
29 changed files with 2100 additions and 48 deletions

152
back/main.py Normal file
View File

@@ -0,0 +1,152 @@
from fastapi import FastAPI
from settings import TORTOISE_ORM
from fastapi.middleware.cors import CORSMiddleware
from tortoise.contrib.fastapi import register_tortoise
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.interval import IntervalTrigger
from tortoise import Tortoise
from contextlib import asynccontextmanager
from apis import app as main_router
import asyncio
import signal
import sys
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
应用生命周期管理函数
- 启动:注册定时任务并启动调度器
- 关闭:优雅关闭调度器与数据库连接
"""
print('项目启动...')
# 初始化数据库连接(使用 Tortoise 直接初始化,确保路由与定时任务可用)
try:
await Tortoise.init(config=TORTOISE_ORM)
print('数据库初始化完成')
except Exception as e:
print(f'数据库初始化失败: {e}')
# 每30分钟保持一次数据库连接活跃
scheduler.add_job(
keep_db_connection_alive,
IntervalTrigger(minutes=30),
id='keep_db_alive',
name='保持数据库连接',
coalesce=True,
misfire_grace_time=30,
)
scheduler.start()
try:
yield
finally:
print('项目结束...')
# 关闭数据库连接
print('关闭数据库连接...')
try:
await asyncio.wait_for(Tortoise.close_connections(), timeout=2)
except asyncio.TimeoutError:
print('关闭数据库连接超时')
except Exception as e:
print(f'关闭数据库连接出错: {e}')
# 关闭调度器
print('关闭调度器...')
try:
if scheduler is not None and hasattr(scheduler, 'shutdown'):
scheduler.shutdown(wait=False)
except Exception as e:
print(f'关闭调度器出错: {e}')
# 创建 FastAPI 应用实例
app = FastAPI(lifespan=lifespan)
# 配置 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# 创建调度器实例
scheduler = AsyncIOScheduler()
# 包含主路由
app.include_router(main_router)
# 注意:使用自定义 lifespan 已在启动时手动初始化数据库。
# 若改回默认事件机制,可重新启用 register_tortoise。
async def keep_db_connection_alive():
"""
保持数据库连接活跃的函数
定期执行简单查询以防止连接超时
"""
try:
conn = Tortoise.get_connection("default")
await conn.execute_query("SELECT 1")
print("数据库连接检查成功")
except Exception as e:
print(f"数据库连接检查失败: {e}")
def signal_handler():
"""
处理终止信号,确保资源正确释放
"""
async def shutdown():
print("收到终止信号,开始优雅关闭...")
# 关闭数据库连接
print("关闭数据库连接...")
try:
await Tortoise.close_connections()
except Exception as e:
print(f"关闭数据库连接时出错: {e}")
# 关闭调度器
print("关闭调度器...")
try:
scheduler.shutdown()
except Exception as e:
print(f"关闭调度器时出错: {e}")
print("所有资源已关闭,程序退出")
sys.exit(0)
loop = asyncio.get_event_loop()
loop.create_task(shutdown())
# 给异步任务一些时间完成
loop.run_until_complete(asyncio.sleep(2))
sys.exit(0)
if __name__ == '__main__':
from uvicorn import run
# 注册信号处理
for sig in (signal.SIGINT, signal.SIGTERM):
signal.signal(sig, lambda sig, frame: signal_handler())
run(
'main:app',
host='0.0.0.0',
port=6060,
reload=False,
workers=1,
# loop='uvloop',
http='httptools',
limit_concurrency=10000,
backlog=4096,
timeout_keep_alive=5
)