"""request_id 关联中间件(ARCH §9.3 / CLAUDE.md)。 每请求生成/透传 request_id,绑入 structlog contextvars,并回写响应头, 错误信封也带上同一 id,便于端到端 grep。 """ from __future__ import annotations import uuid from collections.abc import Awaitable, Callable import structlog from starlette.requests import Request from starlette.responses import Response REQUEST_ID_HEADER = "x-request-id" async def request_id_middleware( request: Request, call_next: Callable[[Request], Awaitable[Response]] ) -> Response: request_id = request.headers.get(REQUEST_ID_HEADER) or uuid.uuid4().hex structlog.contextvars.clear_contextvars() structlog.contextvars.bind_contextvars(request_id=request_id) request.state.request_id = request_id response = await call_next(request) response.headers[REQUEST_ID_HEADER] = request_id return response