fix: complete caller analytics reliability remediation

This commit is contained in:
hectorzhao
2026-09-01 10:03:29 +08:00
parent a116926867
commit 7f8825cf3a
25 changed files with 850 additions and 202 deletions
+43 -2
View File
@@ -2,8 +2,8 @@
日期:2026-08-31
版本:V1.1(按用户修订后的业务口径
状态:设计文档已完成;代码、数据库迁移、真实联调与上线均待实施
版本:V1.2(整改实施版
状态:整改代码与部署方案已完成;最终上线与真实验收结果见对应日期的交付报告
实施更新(2026-08-31):独立分析链路、API、页面和测试脚本已编写;部署与真实验收结果以实施状态及发布报告为准,上述为方案编制时状态。
@@ -219,3 +219,44 @@
- 实际当前OpenSIPS路由只选择一次落地,没有切换重试流程;采集标记单attempt,状态层支持多attempt且有测试,未来新增真实重试必须同步采集独立attemptId,不能直接复用单attempt钩子。
- 历史无过程证据的话单不自动导入完整统计。页面显示新采集生效说明,旧数据不可用不等于呼叫数为0;历史补录仅接受已核验来源的RECONCILE,不接受旧固定时长CDR。
- 告警通过独立进程环境变量配置三个低率阈值和前窗下降百分点;采用样本/未结束占比门槛、连续三次评估及三次恢复,站内展示,不执行停号换路。后续应按实际业务校准默认阈值。
## 13. V1.2 整改落地规范(2026-09-01
本节覆盖V1.1实施后专项核对发现的问题,并作为运行实现的约束。原有计费、余额、路由决策和旧CDR生成语义不在本次整改范围内。
### 13.1 应答证据和生命周期
- 初始INVITE的2xx只证明已接通,不直接证明应答。只有匹配已建立对话的ACK产生`TALK_START`,之后的权威结束时间或对话存活观察才能形成正通话时长。
- 180/183后以非2xx结束时,通话时长确定为0;收到2xx但缺少ACK或最终时长证据时,单列`durationUnknownCalls`,两个应答率返回null。
- 新事件带`schemaVersion=2`、nodeId、bootId、receivedAt及证据版本。业务呼叫以显式`CLOSE`结束;单个线路尝试结束不能提前关闭原始呼叫。
- 原始视角和落地视角继续分开计数。当前路由仍只有一个真实出局尝试;未来增加重试必须为每次尝试生成独立attemptId。
### 13.2 完整性、可靠性和资源边界
- OpenSIPS的两个分析事件发射器都累加`cra_event_total`。采集器将生产计数与成功写入独立Stream的计数核对;不一致、生产进程重启、日志截断/轮转、无效记录、队列积压均进入降级状态。
- 缺口写入`caller_analysis_gaps`,毒消息写入`caller_analysis_dead_letters`。毒消息持久化后ACK,避免无限阻塞消费组;缺口未由运维核实关闭前,相关窗口比例不可用。
- 分析Stream迁移到B机独立Redis实例`127.0.0.1:6381`,使用AOF everysec、RDB、noeviction和256MB上限,不与计费热路径共享内存淘汰策略。发布前备份既有独立实例,服务和维护定时器纳入开机目标。
- 原始事件默认保留30天、呼叫状态90天、分钟桶400天;已解决缺口和死信保留90天。定时维护先统计后事务删除,OPEN记录不自动删除。
- Stream仅在消费组pending为0时近似裁剪,默认上限100万条。数据库提交成功后才ACK;重领和重放由事件唯一键与事务差值更新保证幂等。
### 13.3 API、页面和告警
- API返回`analysisRevision=caller-analytics-r2`、snapshotId、baseFilters、numberFilters、coverageStatus、dataThrough、lagMs、缺口和指标可用性。窗口不是连续完整覆盖时,三个比例统一返回null。
- 号码排序使用业务排序键、caller、customerId的固定次序;详情和拆分在同一数据库事务快照读取,拆分超过500组合时明确返回截断标志。
- 落地主叫增加供应商筛选;原始主叫禁止混用供应商及落地网关筛选。页面分别显示接通未知、时长未知和暂定应答,并把初始INVITE结果与对话结束原因分开展示。
- 站内告警按规则独立保存,使用固定分钟窗键,连续三个不同评估窗触发、连续三个窗恢复。只在最近15分钟、无维度缩窄且连续覆盖的号码全量范围展示;采集降级时告警置为SUSPENDED并停止业务触发。
### 13.4 新增验收用例
| ID | 场景 | 预期 |
| --- | --- | --- |
| CRA-025 | 初始INVITE收到200但从未收到ACK,随后结束 | C=1;A不强判;时长未知=1;应答率为null |
| CRA-026 | ACK后500ms内结束 | TALK_START至结束为正毫秒时长,A=1 |
| CRA-027 | 一个原始呼叫第一尝试失败、第二尝试应答 | 原始T=1且关闭发生在尝试耗尽/业务结束后;落地T=2 |
| CRA-028 | OpenSIPS发射器计数高于采集计数 | coverageStatus=DEGRADED,比例与业务告警不可用 |
| CRA-029 | Stream出现不合法JSON或字段 | 写入持久死信并ACK;消费继续;完整性降级 |
| CRA-030 | Redis pending存在时达到裁剪周期 | 不裁剪;pending清零后才执行有界近似裁剪 |
| CRA-031 | 查询缩窄供应商/网关/地区后存在活动告警 | 不把全量告警贴到缩窄结果;告警范围说明一致 |
| CRA-032 | 同一比例并列且分页重复查询 | 排序和分页结果稳定,snapshotId及筛选回显可追溯 |
| CRA-033 | B机重启 | 独立Redis、分析Worker和维护timer自动恢复,API明确显示恢复期覆盖状态 |
| CRA-034 | 保留维护执行 | 仅删除超过期限的数据;OPEN缺口/死信保留;分钟桶和状态仍可查询 |