Files
lisglosips/docs/CDR_REDIS_STREAM_RUNBOOK.md
T

109 lines
3.8 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.
# CDR Redis Stream Runbook
> 任务:S22 - CDR Redis Stream
> 完成时间:2026-06-21 19:34 +08:00
## 1. 目标
S22 建立原始 CDR 的 Redis Stream 契约和可靠消费基础,不做计费、不扣余额、不写正式 rated CDR。计费与余额扣减留给 S23。
## 2. Redis Key
| Key | 用途 |
| --- | --- |
| `stream:cdr_payload` | OpenSIPS 写入的原始 CDR Stream |
| `stream:cdr_deadletter` | CDR Worker 校验或处理失败后的死信 Stream |
| `billing-workers` | `stream:cdr_payload` 的 Consumer Group |
| `lock:cdr:{event_id}` | Worker 处理幂等占位,避免同一 `event_id` 重复处理 |
## 3. 事件字段
S22 事件 schema version 为 `1`。必填字段:
```text
schema_version
event_id
idempotency_key
call_id
node_id
opensips_instance
ingress_a_ip
rtpengine_node
source_ip
sip_code
hangup_reason
created_at
```
多 A 预留字段已经纳入契约:
- `node_id`A 节点 ID,当前单 A 为 `a1`
- `opensips_instance`OpenSIPS 实例名,当前为 `opensips-a1`
- `ingress_a_ip`:接收 SIP 的 A 节点地址,当前为 `100.90.90.90`
- `rtpengine_node`:媒体节点,当前每台 A 绑定本机 RTPEngine,因此为 `a1`
S22 阶段 A 端尚未进入真实落地路由,因此失败 CDR 的供应商、录音、应答时间等字段使用 `none``0` 占位。S23/S24 后续在不破坏 schema 的前提下补充真实计费和录音字段。
## 4. Producer
Server A OpenSIPS 在 `route[S20_CDR_XADD]` 中执行:
```text
XADD stream:cdr_payload * schema_version 1 ... created_at <unix>
```
当前 A 端字段已从 S20 冒烟格式升级为 S22 正式契约。A 端配置备份:
```text
/var/backups/lisglosips-s22/20260621T113157Z/opensips.cfg
```
## 5. Consumer
`packages/redis/src/cdr-stream.ts` 提供:
- `ensureCdrConsumerGroup`
- `publishCdrEvent`
- `parseCdrStreamEvent`
- `processCdrBatch`
- `processPendingCdrBatch`
`apps/worker-cdr` 已从骨架改为 Redis Stream Worker
1. 读取 `REDIS_URL`
2. 确认 `billing-workers` Consumer Group。
3. 先用 `XAUTOCLAIM` 重领 Pending,再用 `XREADGROUP` 读取新消息。
4.`lock:cdr:{event_id}` 做幂等占位。
5. 处理成功或重复消息后 `XACK`
6. 校验失败或处理异常时写入 `stream:cdr_deadletter``XACK` 原消息。
当前 handler 只记录并接受原始 CDR,不执行计费和余额扣减。
## 6. 验证结果
- 本地 `packages/redis/src/cdr-stream.spec.ts` 6 条测试通过,覆盖发布、解析、Consumer Group 幂等创建、`XREADGROUP`/`XACK`、重复 `event_id`、死信和 `XAUTOCLAIM` Pending 重领。
- `corepack pnpm@10.33.0 lint` 通过。
- `corepack pnpm@10.33.0 typecheck` 通过。
- `corepack pnpm@10.33.0 build` 通过。
- A `opensips -C -f /etc/opensips/opensips.cfg` 通过,`opensips.service` active。
- Redis `XGROUP CREATE stream:cdr_payload billing-workers 0 MKSTREAM` 返回 `OK`
- Redis `XINFO GROUPS stream:cdr_payload` 显示 `billing-workers`pending 为 `0`
- T 发起 INVITE 后,A 返回 `SIP/2.0 503 Config Missing`Redis Stream 最新事件包含 `schema_version=1``idempotency_key``node_id=a1``opensips_instance=opensips-a1``ingress_a_ip=100.90.90.90``rtpengine_node=a1`
## 7. 回滚
代码回滚:
- 恢复 `packages/redis/src/index.ts``packages/redis/src/cdr-stream.ts``packages/redis/src/cdr-stream.spec.ts``apps/worker-cdr/src/main.ts`
- 重新执行 `corepack pnpm@10.33.0 build`
Server A 回滚:
```bash
sudo cp -a /var/backups/lisglosips-s22/20260621T113157Z/opensips.cfg /etc/opensips/opensips.cfg
sudo opensips -C -f /etc/opensips/opensips.cfg
sudo systemctl restart opensips
```
Redis Consumer Group 可保留,不影响 Producer;如必须移除,应先确认没有未处理 Pending,再使用受控 Redis 维护窗口删除 group。S22 不删除 Stream 数据。