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

80 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 队列监控接入说明(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):
```yaml
# prometheus.yml
scrape_configs:
- job_name: lingxi-api
metrics_path: /api/v1/metrics
static_configs:
- targets: ['127.0.0.1:3000']
```
```bash
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. 校验规则语法:
```bash
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` 可读到上述指标、规则文件可加载。