Files
kami_apple_exchage/backend/app/main.py
danial 5c486e34d3 docs(项目): 添加项目文档并进行代码调整
- 新增 CODEBUDDY.md、GEMINI.md、GEMINI_CN.md 等项目文档
- 更新 Dockerfile 和其他配置文件
- 优化部分代码结构,如 orders.py、tasks.py 等
- 新增 .dockerignore 文件
2025-09-12 19:38:24 +08:00

297 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Apple Gift Card Exchange Backend
FastAPI应用程序入口点
"""
import asyncio
import os
import sys
from contextlib import asynccontextmanager
from pathlib import Path
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from app.api import api_router
from app.core.redis_manager import redis_manager
from app.core.config import get_settings
from app.core.database import close_database, init_database
from app.core.exceptions import setup_exception_handlers
from app.core.graceful_shutdown import graceful_shutdown_manager
from app.core.log import get_logger
from app.core.middleware import (
setup_cors_middleware,
setup_custom_middleware,
add_api_logging_middleware,
add_metrics_middleware,
)
from app.core.telemetry import (
initialize_telemetry,
shutdown_telemetry,
)
# 设置控制台编码为UTF-8确保中文字符正常显示
if sys.platform.startswith("win"):
os.system("chcp 65001 > nul") # Windows设置控制台为UTF-8
settings = get_settings()
logger = get_logger(__name__)
# 请求跟踪
active_requests = set()
shutdown_requested = False
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
logger.info("🚀 启动Apple Gift Card Exchange Backend")
try:
# 设置优雅关闭信号处理器
graceful_shutdown_manager.setup_signal_handlers()
# 按照优先级注册关闭回调(相反顺序关闭)
# 1. 先关闭 OpenTelemetry需要首先停止新的追踪和指标收集
graceful_shutdown_manager.register_shutdown_callback(shutdown_telemetry)
# 2. 然后关闭 Redis可能被 OpenTelemetry 使用)
graceful_shutdown_manager.register_shutdown_callback(redis_manager.close_redis)
# 3. 最后关闭数据库(基础资源)
graceful_shutdown_manager.register_shutdown_callback(close_database)
logger.info("✅ 优雅关闭机制已设置")
# 初始化 OpenTelemetry
await initialize_telemetry()
logger.info("✅ OpenTelemetry 初始化完成")
# 初始化数据库
await init_database()
logger.info("✅ 数据库初始化完成")
# 创建数据库表
from app.models import create_tables
await create_tables()
logger.info("✅ 数据库表创建完成")
# 创建必要的目录
Path(settings.UPLOAD_DIR).mkdir(parents=True, exist_ok=True)
Path(settings.SNAPSHOT_DIR).mkdir(parents=True, exist_ok=True)
Path(settings.HTML_DIR).mkdir(parents=True, exist_ok=True)
logger.info("✅ 文件目录创建完成")
# 应用启动完成
logger.info("🎉 应用启动完成")
yield
# 应用关闭清理 - 优雅关闭已经处理了大部分清理工作
logger.info("🔄 开始应用关闭清理...")
global shutdown_requested
shutdown_requested = True
# 等待活跃请求完成
max_wait_time = 30
wait_interval = 0.5
waited_time = 0
while active_requests and waited_time < max_wait_time:
logger.info(
f"⏳ 等待 {len(active_requests)} 个活跃请求完成... ({waited_time:.1f}s/{max_wait_time}s)"
)
await asyncio.sleep(wait_interval)
waited_time += wait_interval
if active_requests:
logger.warning(f"⚠️ 仍有 {len(active_requests)} 个请求未完成,强制关闭")
else:
logger.info("✅ 所有活跃请求已完成")
logger.info("👋 应用关闭完成")
except Exception as e:
logger.error(f"❌ 应用生命周期管理异常: {e}")
raise
def create_app() -> FastAPI:
"""创建FastAPI应用实例"""
app = FastAPI(
title=settings.APP_NAME,
version=settings.APP_VERSION,
description="Apple礼品卡兑换服务后端API - 基于FastAPI的现代异步微服务架构",
summary="Apple Gift Card Exchange Backend API",
docs_url="/docs" if settings.DEBUG else None,
redoc_url="/redoc" if settings.DEBUG else None,
openapi_url="/openapi.json" if settings.DEBUG else None,
lifespan=lifespan,
servers=[
{
"url": f"http://{settings.HOST}:{settings.PORT}",
"description": f"{settings.ENVIRONMENT.value.title()} server",
}
],
openapi_tags=[
{
"name": "Health Check",
"description": "System health status check related interfaces",
},
{
"name": "Thread Pool Management",
"description": "Thread pool configuration and management related interfaces",
},
{
"name": "Timeout Configuration",
"description": "System timeout parameter configuration related interfaces",
},
{
"name": "Crawler Management",
"description": "Crawler service control and status management related interfaces",
},
{
"name": "System Configuration",
"description": "System global configuration management related interfaces",
},
{
"name": "User Management",
"description": "User account and permission management related interfaces",
},
{
"name": "Order Management",
"description": "Order processing and status management related interfaces",
},
{
"name": "Playwright Service",
"description": "Browser automation service related interfaces",
},
{
"name": "Link Management",
"description": "Link management related interfaces",
},
{
"name": "Gift Card Management",
"description": "Gift card management related interfaces",
},
{
"name": "User Data Management",
"description": "User data management related interfaces",
},
],
)
# 添加中间件
setup_middleware(app)
# 添加路由
setup_routes(app)
# 添加异常处理器
setup_exception_handlers(app)
return app
def setup_middleware(app: FastAPI):
"""设置中间件"""
# 请求跟踪中间件
@app.middleware("http")
async def request_tracking_middleware(request, call_next):
"""请求跟踪中间件 - 跟踪活跃请求"""
if shutdown_requested:
from fastapi import HTTPException
raise HTTPException(status_code=503, detail="服务正在关闭中,请稍后重试")
# 生成请求ID并添加到活跃请求集合
request_id = f"{id(request)}_{asyncio.current_task()}"
active_requests.add(request_id)
try:
response = await call_next(request)
return response
finally:
# 请求完成后从活跃请求集合中移除
active_requests.discard(request_id)
# 信任主机中间件
if settings.ALLOWED_HOSTS != ["*"]:
app.add_middleware(TrustedHostMiddleware, allowed_hosts=settings.ALLOWED_HOSTS)
# 设置CORS中间件
setup_cors_middleware(app)
# 设置自定义中间件(日志、安全头等)
setup_custom_middleware(app)
# # 设置 OpenTelemetry 中间件
# add_metrics_middleware(app)
# 添加API日志记录中间件
add_api_logging_middleware(app)
def setup_routes(app: FastAPI):
"""设置路由"""
# API路由
app.include_router(api_router, prefix="/api")
# 健康检查端点
@app.get("/", tags=["root"])
async def root():
"""根路径健康检查"""
base_url = f"http://{settings.HOST}:{settings.PORT}"
return {
"message": "Apple Gift Card Exchange Backend",
"version": settings.APP_VERSION,
"status": "healthy",
"environment": settings.ENVIRONMENT.value,
"api_docs": {
"swagger_ui": (
f"{base_url}/docs" if settings.DEBUG else "仅在开发环境可用"
),
"redoc": f"{base_url}/redoc" if settings.DEBUG else "仅在开发环境可用",
"openapi_json": (
f"{base_url}/openapi.json" if settings.DEBUG else "仅在开发环境可用"
),
"openapi_version": "3.0.0",
"specification": "OpenAPI 3.0.0 Specification",
},
"api_endpoints": {
"base_api": f"{base_url}/api",
"health_check": f"{base_url}/",
"api_v1": f"{base_url}/api/v1",
},
"server_info": {
"host": settings.HOST,
"port": settings.PORT,
"debug_mode": settings.DEBUG,
},
}
# 创建应用实例
app = create_app()
# 导出常用函数供其他模块使用
__all__ = ["app", "active_requests", "shutdown_requested"]
if __name__ == "__main__":
uvicorn.run(
"app.main:app",
host=settings.HOST,
port=settings.PORT,
reload=settings.DEBUG,
workers=1 if settings.DEBUG else settings.WORKERS,
log_level=settings.LOG_LEVEL.lower(),
access_log=True,
)