架构重构:拆分 core/ops/DBManager,统一 SQLite 锁,DEB 改进,新增注意力模型
- web/core.py 858→236行,拆出 schemas/middleware/auth/diagnostics - ops_api.py 2876→4个 domain 模块 (users/payments/health/config) - DBManager Supabase HTTP 调用提取到 SupabaseAdminClient - 新增 LockedSQLiteConnection 统一多进程读写锁 - 新增 WeatherCacheManager 替代 12 个独立缓存字典 - METAR 缓存迁移至统一缓存管理器 - analysis_service 提取 _build_intraday_meteorology 到独立模块 - DEB 改进:偏差惩罚、分歧回退、自适应 lookback (MAE ↓12.6%) - 新增 PyTorch 注意力模型 deb_attention.py (数据积累后启用) - 新增 torch 到 requirements.lock
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""HTTP middlewares for the PolyWeather FastAPI application."""
|
||||
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
from fastapi import Request
|
||||
from fastapi.responses import Response
|
||||
|
||||
from src.utils.metrics import counter_inc, histogram_observe
|
||||
|
||||
|
||||
async def metrics_middleware(request: Request, call_next):
|
||||
started = time.perf_counter()
|
||||
try:
|
||||
response = await call_next(request)
|
||||
except Exception:
|
||||
duration_ms = (time.perf_counter() - started) * 1000.0
|
||||
counter_inc(
|
||||
"polyweather_http_requests_total",
|
||||
method=request.method,
|
||||
path=request.url.path,
|
||||
status="500",
|
||||
)
|
||||
histogram_observe(
|
||||
"polyweather_http_request_duration_ms",
|
||||
duration_ms,
|
||||
method=request.method,
|
||||
path=request.url.path,
|
||||
status="500",
|
||||
)
|
||||
raise
|
||||
|
||||
duration_ms = (time.perf_counter() - started) * 1000.0
|
||||
status_code = str(response.status_code)
|
||||
counter_inc(
|
||||
"polyweather_http_requests_total",
|
||||
method=request.method,
|
||||
path=request.url.path,
|
||||
status=status_code,
|
||||
)
|
||||
histogram_observe(
|
||||
"polyweather_http_request_duration_ms",
|
||||
duration_ms,
|
||||
method=request.method,
|
||||
path=request.url.path,
|
||||
status=status_code,
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
async def etag_middleware(request: Request, call_next):
|
||||
"""Add ETag to GET /api/* responses; return 304 on If-None-Match hit."""
|
||||
response = await call_next(request)
|
||||
|
||||
if request.method != "GET" or response.status_code != 200:
|
||||
return response
|
||||
|
||||
path = request.url.path
|
||||
if not path.startswith("/api/") or path.endswith("/stream"):
|
||||
return response
|
||||
|
||||
body = getattr(response, "body", None) or b""
|
||||
if not body:
|
||||
return response
|
||||
|
||||
try:
|
||||
etag = hashlib.md5(body).hexdigest()
|
||||
except Exception:
|
||||
return response
|
||||
|
||||
etag_value = f'"{etag}"'
|
||||
if_none_match = request.headers.get("If-None-Match", "")
|
||||
if if_none_match == etag_value:
|
||||
return Response(status_code=304, headers={"ETag": etag_value})
|
||||
|
||||
response.headers["ETag"] = etag_value
|
||||
response.headers["Cache-Control"] = "private, max-age=30"
|
||||
return response
|
||||
Reference in New Issue
Block a user