"""接口指标埋点:有界事件队列 + 纯 ASGI 中间件。 每个 HTTP 请求测总耗时、抓路由模板 + 状态码,非阻塞塞进有界队列;由 observe_worker 后台批量上报到 OpenObserve。请求路径上无任何 I/O。未配置观测时中间件直接透传。 """ from __future__ import annotations import asyncio from app.core.config import settings # 有界事件队列(懒创建,见 get_queue):首次取用时在运行中的 loop 里建,避免 import 期 # 无 loop 的边角问题;put_nowait/get_nowait 不需运行中的 loop → 可在无 loop 下测试。 _queue: asyncio.Queue[dict] | None = None # 队列满时的丢弃计数,worker 定期取出打日志。 _dropped = 0 def get_queue() -> asyncio.Queue[dict]: """返回全局有界事件队列(懒创建)。测试可 monkeypatch 模块级 _queue 换成小队列。""" global _queue if _queue is None: _queue = asyncio.Queue(maxsize=settings.OBSERVE_QUEUE_MAX) return _queue def take_dropped() -> int: """取出并清零累计丢弃数(供 worker 打点)。""" global _dropped n, _dropped = _dropped, 0 return n def record_event(event: dict) -> None: """非阻塞入队;队列满则丢弃当前事件并计数。永不抛异常、永不阻塞请求。""" global _dropped try: get_queue().put_nowait(event) except asyncio.QueueFull: _dropped += 1