"""Async correlation ID context variable and helpers.""" import contextvars import uuid from fastapi import Request from starlette.middleware.base import BaseHTTPMiddleware CORRELATION_ID: contextvars.ContextVar[str] = contextvars.ContextVar("correlation_id") def get_correlation_id() -> str: """Return the current correlation ID or generate a new UUID.""" try: return CORRELATION_ID.get() except LookupError: return str(uuid.uuid4()) class CorrelationIdMiddleware(BaseHTTPMiddleware): """Set correlation ID from X-Request-ID header or generate a new UUID.""" async def dispatch(self, request: Request, call_next): request_id = request.headers.get("X-Request-ID") correlation_id = request_id or str(uuid.uuid4()) token = CORRELATION_ID.set(correlation_id) try: response = await call_next(request) response.headers["X-Request-ID"] = correlation_id return response finally: CORRELATION_ID.reset(token)