9c6c477f55
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 2m22s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 2m24s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 37s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 4m3s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
P0 关键修复: - P0-1: 注册接口添加 RateLimitMiddleware 限流保护 - P0-3: /metrics 端点添加 JWT 认证(移除匿名访问) - P0-4: 修复 Celery 任务名冲突(generation_task vs generate_video) - P1-5: JWT logout token 黑名单机制 P1 修复: - P1-1: forgot_password 硬编码 localhost → 使用 settings.APP_BASE_URL - P1-2: generation.py 直接创建 DB 连接 → 使用依赖注入 - P1-6: Image.open() 未关闭 → 统一使用 with 语句 - P1-7: 订阅续费事务修复 P2 代码质量: - P2-1: 修复 EditingMode 枚举重复定义 → 统一引用 shared 包 - P2-2: 修复 SMTP_FRON_NAME → SMTP_FROM_NAME 拼写 - P2-3: UserModel subscription_quota 类型统一为 float - P2-4: .env.production DATABASE_MAX_OVERFLOW 30 → 10 - 清理 15 处 except:pass(保留 2 处有注释说明的) - 禁用 SVG 上传(XSS 风险) - 删除 decode_token_unsafe() 不安全函数 - 简化 /ready 端点 - 删除 8 处死代码、10 个空文件/模块 - 合并 3 对 100% 重复函数 - 对齐 6 个废弃环境变量 v2 修复(代码审查后): - 修复密码重置路由路径: /password/forgot → /forgot-password, /password/reset → /reset-password(与前端 API 对齐) - 合并 _check_project_access: asset_libraries.py 和 edit_plans.py 中的重复函数统一到 _helpers.py(含空字符串守卫 + 中文错误信息) - 顺手修复: HTTPException 统一从 fastapi 导入(替换 starlette 导入) - OSS_ENDPOINT 拼写修复拆分为单独 PR,本 PR 不包含
105 lines
3.1 KiB
Python
105 lines
3.1 KiB
Python
"""
|
||
性能监控中间件
|
||
"""
|
||
|
||
import logging
|
||
import time
|
||
from typing import Callable
|
||
|
||
from fastapi import Request
|
||
from starlette.middleware.base import BaseHTTPMiddleware
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class PerformanceMonitoringMiddleware(BaseHTTPMiddleware):
|
||
"""性能监控中间件"""
|
||
|
||
def __init__(self, app, slow_request_threshold: float = 1.0):
|
||
super().__init__(app)
|
||
self.slow_request_threshold = slow_request_threshold # 慢请求阈值(秒)
|
||
|
||
async def dispatch(self, request: Request, call_next: Callable):
|
||
# 记录请求开始时间
|
||
start_time = time.time()
|
||
|
||
# 生成请求 ID
|
||
request_id = self._generate_request_id()
|
||
request.state.request_id = request_id
|
||
|
||
# 处理请求
|
||
try:
|
||
response = await call_next(request)
|
||
|
||
# 计算处理时间
|
||
process_time = time.time() - start_time
|
||
|
||
# 添加响应头
|
||
response.headers["X-Request-ID"] = request_id
|
||
response.headers["X-Process-Time"] = f"{process_time:.3f}"
|
||
|
||
# 记录慢请求
|
||
if process_time > self.slow_request_threshold:
|
||
logger.warning(
|
||
f"Slow request detected: {request.method} {request.url.path} "
|
||
f"took {process_time:.3f}s (threshold: {self.slow_request_threshold}s) "
|
||
f"[request_id={request_id}]"
|
||
)
|
||
|
||
# 记录请求日志
|
||
logger.info(
|
||
f"{request.method} {request.url.path} "
|
||
f"status={response.status_code} time={process_time:.3f}s "
|
||
f"[request_id={request_id}]"
|
||
)
|
||
|
||
return response
|
||
|
||
except Exception as e:
|
||
process_time = time.time() - start_time
|
||
logger.error(
|
||
f"Request failed: {request.method} {request.url.path} "
|
||
f"error={str(e)} time={process_time:.3f}s "
|
||
f"[request_id={request_id}]",
|
||
exc_info=True,
|
||
)
|
||
raise
|
||
|
||
def _generate_request_id(self) -> str:
|
||
"""生成请求 ID"""
|
||
import uuid
|
||
|
||
return str(uuid.uuid4())
|
||
|
||
|
||
class DatabaseQueryLogger:
|
||
"""数据库查询日志记录器"""
|
||
|
||
def __init__(self):
|
||
self.queries = []
|
||
self.total_time = 0
|
||
|
||
def log_query(self, query: str, params: tuple, duration: float):
|
||
"""记录查询"""
|
||
self.queries.append(
|
||
{
|
||
"query": query,
|
||
"params": params,
|
||
"duration": duration,
|
||
}
|
||
)
|
||
self.total_time += duration
|
||
|
||
# 记录慢查询(超过 100ms)
|
||
if duration > 0.1:
|
||
logger.warning(f"Slow query detected: {query[:100]}... " f"took {duration:.3f}s with params {params}")
|
||
|
||
def get_stats(self):
|
||
"""获取统计信息"""
|
||
return {
|
||
"total_queries": len(self.queries),
|
||
"total_time": self.total_time,
|
||
"avg_time": self.total_time / len(self.queries) if self.queries else 0,
|
||
"slow_queries": len([q for q in self.queries if q["duration"] > 0.1]),
|
||
}
|