保定ai问答主体项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bd_ai_fastapi/app/__init__.py

143 lines
4.3 KiB

3 months ago
import os
import logging
3 months ago
from contextlib import asynccontextmanager
from fastapi import FastAPI
from tortoise import Tortoise
from redis.asyncio import Redis
3 months ago
from fastapi.staticfiles import StaticFiles
from aiomysql import create_pool, OperationalError as AiomysqlOperationalError
3 months ago
from app.core.exceptions import SettingNotFound
from app.core.init_app import (
init_data,
make_middlewares,
register_exceptions,
register_routers,
)
3 months ago
try:
from app.settings.config import settings
except ImportError:
raise SettingNotFound("Can not import settings")
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
3 months ago
@asynccontextmanager
async def lifespan(app: FastAPI):
# 初始化资源
app.state.mysql_pool = None
app.state.redis_client = None
3 months ago
try:
1 month ago
# 初始化 MySQL 连接池
3 months ago
app.state.mysql_pool = await create_pool(
host=settings.FLOW_MYSQL_HOST,
port=settings.FLOW_MYSQL_PORT,
user=settings.FLOW_MYSQL_USER,
password=settings.FLOW_MYSQL_PASSWORD,
db=settings.FLOW_MYSQL_DB,
# 核心并发参数
1 month ago
minsize=15, # 初始保持20个连接
1 month ago
maxsize=50, # 最大连接数
# 连接管理优化
1 month ago
pool_recycle=100, # 180秒回收连接
connect_timeout=15, # 连接超时时间
# 其他优化
charset='utf8mb4',
echo=False,
3 months ago
)
# 验证连接有效性
3 months ago
async with app.state.mysql_pool.acquire() as conn:
await conn.ping()
logger.info("✅ MySQL 连接池初始化成功")
except AiomysqlOperationalError as e:
logger.error(f"❌ MySQL 连接池初始化失败: 数据库操作错误 - {str(e)}")
raise
3 months ago
except Exception as e:
logger.error(f"❌ MySQL 连接池初始化失败: 未知错误 - {str(e)}")
3 months ago
raise
3 months ago
try:
1 month ago
# 初始化 Redis 连接
3 months ago
app.state.redis_client = Redis(
host=settings.REDIS_HOST,
port=settings.REDIS_PORT,
db=settings.REDIS_DB,
decode_responses=True,
password=settings.REDIS_PASSWORD,
socket_connect_timeout=5,
socket_keepalive=True,
retry_on_timeout=True,
1 month ago
# 连接池参数
1 month ago
max_connections=1024, # Redis连接池最大连接数
1 month ago
health_check_interval=30,
retry_on_error=[ConnectionError, TimeoutError], # 重试错误类型
single_connection_client=False, # 不使用单连接客户端
auto_close_connection_pool=True # 自动关闭连接池
3 months ago
)
3 months ago
await app.state.redis_client.ping()
logger.info("✅ Redis 连接成功")
3 months ago
except Exception as e:
logger.error(f"❌ Redis 连接失败: {str(e)}")
try:
await init_data()
except Exception as e:
logger.error(f"❌ 初始化数据失败: {str(e)}")
raise
3 months ago
yield
# 资源清理
if app.state.redis_client:
try:
await app.state.redis_client.close()
logger.info("🛑 Redis 连接已关闭")
except Exception as e:
logger.warning(f" Redis 关闭失败: {str(e)}")
if app.state.mysql_pool:
try:
app.state.mysql_pool.close()
await app.state.mysql_pool.wait_closed()
logger.info("🛑 MySQL 连接池已关闭")
except Exception as e:
logger.warning(f" MySQL 连接池关闭失败: {str(e)}")
try:
await Tortoise.close_connections()
logger.info("🛑 Tortoise 连接已关闭")
except Exception as e:
logger.warning(f" Tortoise 连接关闭失败: {str(e)}")
3 months ago
def create_app() -> FastAPI:
app = FastAPI(
title=settings.APP_TITLE,
description=settings.APP_DESCRIPTION,
version=settings.VERSION,
openapi_url="/openapi.json",
middleware=make_middlewares(),
lifespan=lifespan,
)
static_dir = os.path.join(settings.BASE_DIR, 'web', 'public', 'resource')
if os.path.exists(static_dir):
app.mount("/resource", StaticFiles(directory=static_dir), name="resource")
else:
logger.warning(f" 静态文件目录不存在: {static_dir}")
3 months ago
register_exceptions(app)
register_routers(app, prefix="/api")
return app
app = create_app()