Files
group_xinghuo_jinrong/app/main.py
T

70 lines
2.5 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.
"""FastAPI 入口(B7 集成):路由挂载、trace 中间件、lifespan、统一错误体。
lifespan(B7 挂账⑤⑥):
- 启动期校验:非 development 环境且鉴权工厂仍为 debug 头实现 → 拒绝启动
(T-01 接入 JWT 后置 deps.AUTH_FACTORY_IS_DEBUG=False 放行);
- Redis 网关单例注册(惰性连接,publish/DEL 失败降级不阻塞业务);
- shutdown 统一 dispose 数据库引擎(utils/db 工厂,B6 复审 P3 泄漏收口)。
trace:X-Trace-Id 透传/生成 + 响应头回写(trace.py 约束:call_next 前 set,
同步路由线程池由 anyio 传播,一致性 B8 断言兜底)。
"""
from __future__ import annotations
import re
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from app.api import deps
from app.api.risk import router as risk_router
from app.api.simulate import router as simulate_router
from app.config.settings import settings
from app.service.risk import redis_gateway
from app.utils.db import dispose_engines
from app.utils.response import register_error_handlers
from app.utils.trace import new_trace, reset_trace, set_trace
# 透传外部 X-Trace-Id 的格式白名单(防响应头注入;不合规一律新生成)
_TRACE_ID_PATTERN = re.compile(r"^[A-Za-z0-9._-]{1,64}$")
@asynccontextmanager
async def lifespan(_: FastAPI):
if settings.app_env != "development" and deps.AUTH_FACTORY_IS_DEBUG:
raise RuntimeError(
"debug auth factory is wired but app_env is not 'development'; "
"deploy T-01 JWT auth first or set app_env=development"
)
redis_gateway.set_gateway(redis_gateway.RedisGateway())
try:
yield
finally:
redis_gateway.set_gateway(None)
dispose_engines()
app = FastAPI(title="JinRong Agent Platform", version="0.2.0", lifespan=lifespan)
register_error_handlers(app)
app.include_router(risk_router)
app.include_router(simulate_router)
@app.middleware("http")
async def trace_middleware(request: Request, call_next):
"""trace_id 贯通:透传合法 X-Trace-Id,否则生成;响应头回写。"""
incoming = request.headers.get("X-Trace-Id", "")
trace_id = incoming if _TRACE_ID_PATTERN.fullmatch(incoming) else new_trace()
token = set_trace(trace_id)
try:
response = await call_next(request)
finally:
reset_trace(token)
response.headers["X-Trace-Id"] = trace_id
return response
@app.get("/health")
def health():
return {"status": "ok", "env": settings.app_env}