Files
lingxi/infra/monitoring/README.md
T
Stev_Wang 633765f10f
ci / 质量门禁 (push) Successful in 6m4s
feat(media): A6 任务中心 API、SSE 进度与队列骨架
背景:A6-BE-01..05 与 A6-INF-01,打通「提交 → 队列 → SSE 进度 → 完成/失败 → 取消 / 仅重试失败项」闭环,为 B3 / M1 的真实任务提供统一协议。
改动:
- API media 模块:POST/GET /media-tasks、详情、SSE(Last-Event-ID 续推 + 15s 心跳 + 800ms 落库轮询)、取消(只影响未开始项)、仅重试失败项;Idempotency-Key 24h(异步提交 202;同 key 同 body 返回同一任务且不重复审计,不同 body 40902);范围外统一 404;
- 队列骨架:BullMQ 5 九队列(5 组独立启停)、Outbox dispatcher(Redis 锁 + FOR UPDATE SKIP LOCKED + jobId 幂等 + 指数退避/死信)、worker 按 QUEUE 启停、demo 演练处理器(事务 + 行锁 + 取消/重试/幂等)、优雅退出与心跳;
- 监控:GET /api/v1/health/queues、GET /api/v1/metrics(Prometheus 0.0.4)、infra/monitoring 告警规则与接入说明;
- 通用:AuditInterceptor 支持幂等重放 skipAudit(默认行为不变)、AppModule 接线、.env.example 的 QUEUE 语义、bullmq 5.81.5 / worker @prisma/client / worker 覆盖率依赖。
影响面:OpenAPI 新增 6 个端点(openapi:diff 无破坏性变更);API 进程新增 outbox dispatcher 与 metrics/health 路由;worker 新增 BullMQ 消费;未改旧审计导出链路与既有接口。
回滚:回滚提交并停止 worker 新队列消费;task/outbox 新表数据不影响旧功能,可按需保留。
验证:api 单测 257、集成 92(连跑 2 次)、worker 27、shared 197;typecheck / lint / format:check / build / openapi:diff 全绿;本地真实 worker 启用 9 队列心跳,/health/queues、/metrics 实测,/media-tasks 未登录 401。
2026-11-04 21:52:35 +08:00

5.9 KiB
Raw Blame History

队列监控接入说明(A6-INF-01)

本目录提供 BullMQ 队列与 Outbox 投递的 Prometheus 告警规则。M0 阶段只交付指标端点与规则文件, 本机尚未部署 Prometheus / Grafana(技术架构 §4 的观测套件在 T1 阶段落地),后续按下面的步骤接入。

1. 指标端点

用途 地址 说明
Prometheus 抓取 GET /api/v1/metrics text/plain; version=0.0.4; charset=utf-8,由 apps/api/src/infra/queue/queue-metrics.controller.ts 提供
队列健康检查 GET /api/v1/health/queues 9 个队列的计数 / 队首等待秒数 / worker 心跳;Redis 不可用返回 503(错误码 50002)

/health/queues 的 HTTP 状态:依赖异常 503;status=degraded(存在积压但 worker 心跳缺失或陈旧)仍返回 200,由告警规则负责通知。 指标采集失败不会让 /metrics 返回 5xx,而是输出 # 注释行并记日志,保证抓取链不断。

注意:/health、/metrics 均为只读公开端点(@Public()),部署时应在网关限制为内网访问; 进程启动时 @nestjs/swagger 会扫描控制器,/metrics 已用 @ApiExcludeController() 排除出 OpenAPI 契约。

2. 指标清单

指标 类型 标签 含义
lingxi_queue_jobs gauge queue、state(waiting/active/completed/failed/delayed) 队列内各状态任务数
lingxi_queue_oldest_waiting_seconds gauge queue 队首等待任务的等待秒数(无等待任务为 0)
lingxi_queue_failure_ratio gauge queue failed/(failed+completed),无样本为 0
lingxi_worker_heartbeat_age_seconds gauge queue worker 心跳年龄(秒);缺失为 -1
lingxi_outbox_pending_total gauge — outbox_events.published_at IS NULL 的事件数
lingxi_outbox_dead_letter_total gauge — outbox_events.last_error='dead_lettered' 的累计事件数

心跳 key:lingxi:worker:heartbeat:<queueName>(worker 每 10s 续写,TTL 30s)。

队列名口径:指标 / 告警 / 心跳 / QUEUE 环境变量都用逻辑名(media:verify 这类 <域>:<动作>); BullMQ 5.x 禁止队列名与自定义 jobId 含冒号,因此 BullMQ 内部物理队列名把 : 换成 -(media-verify), jobId 用 - 连接(<eventId>-<itemId>)。排查 Redis key 时按物理名找,看指标与告警时按逻辑名。

3. Prometheus 接入步骤

  1. 启动 Prometheus(本机示例;生产按运维 Runbook 挂到 Compose):

    # prometheus.yml
    scrape_configs:
      - job_name: lingxi-api
        metrics_path: /api/v1/metrics
        static_configs:
          - targets: ['127.0.0.1:3000']
    
    prometheus --config.file=prometheus.yml \
      --rules.file=infra/monitoring/queue-alerts.yml   # 或使用 rule_files 引入
    

    rule_files 更常用:在 prometheus.yml 写 rule_files: ['/etc/prometheus/queue-alerts.yml']。 本仓库的 CI / 本地校验可用 promtool check rules infra/monitoring/queue-alerts.yml。

  2. 校验规则语法:

    promtool check rules infra/monitoring/queue-alerts.yml
    
  3. 验证数据:curl -s http://127.0.0.1:3000/api/v1/metrics | grep lingxi_, 再在 Prometheus UI → Graph 查询 lingxi_queue_oldest_waiting_seconds。

4. 告警规则

告警 表达式 持续 级别 处置
LingxiQueueBacklog lingxi_queue_oldest_waiting_seconds > 600 5m warning 确认对应队列组的 worker 是否启动 / 并发是否被长任务占满;必要时扩容 worker(QUEUE=<组名> 单独扩容)
LingxiQueueHighFailureRatio lingxi_queue_failure_ratio > 0.05 10m warning 看失败 job 的 last_error 与 worker 日志;区分业务失败与依赖故障
LingxiWorkerHeartbeatMissing heartbeat_age < 0 或 > 60 2m critical 检查 worker 进程 / QUEUE 分组 / Redis 连通性
LingxiOutboxDeadLetter lingxi_outbox_dead_letter_total > 0 1m critical 查 outbox_events WHERE last_error='dead_lettered',修复 payload / 队列配置后人工补投

5. Grafana(后续)

  • 数据源:Prometheus;面板建议:按 queue 分组的任务数堆叠图、队首等待时长、 失败率、worker 心跳热力图、outbox 待投递 / 死信。
  • 本机暂无 Grafana 实例,M0 验收只要求 curl /api/v1/metrics 可读到上述指标、规则文件可加载。