4a7f24348c
- Add instance_events and health_checks tables with Alembic migration - InstanceEventBus: typed pub/sub singleton with wildcard support - HealthMonitor: async background loop polling containers every 15s - SSE endpoint GET /events/stream with auth and connection limits - Lifecycle hooks in tool_instances.py (create/start/stop/restart/delete) - Structured JSON logging with correlation IDs - 15 new unit tests (EventBus, HealthMonitor, MonitoringModels) Quality gates: pytest 15 new passed, ruff clean
33 lines
1.0 KiB
Python
33 lines
1.0 KiB
Python
"""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)
|