7 Commits
Author SHA1 Message Date
chengqian 96bcd3e46f fix(channel):修复渠道更新key后无法立即生效 2026-08-28 16:55:28 +08:00
chengqian a5e2ecf527 fix(dispatch): 渠道健康聚合只统计有真实上报的模型,降级时保留库中旧值
渠道展示分是目录内全部模型 succ_ewma 的算术平均,而无流量模型读到的是乐观默认满分。
20 个模型的渠道死掉 1 个(succ→0.05)仍能算出 avgSucc≈0.95、91 分绿灯,恰好掩盖了
模型级熔断要隔离的典型场景。改为只统计 HasHealth 的模型;全渠道无真实上报时
Counted=0,保留库中上一次的分数而不是用默认满分覆盖历史结论。

Redis 读失败(Degraded)时跳过落盘并打 Warning:照常落盘会把全渠道健康分刷成 100,
连带 chn_health_snapshots 把假象写进历史趋势,事故期间的曲线反而全绿。自动禁用判定
一并跳过——该操作不可逆,不能基于不可信读值触发。

聚合逻辑抽成纯函数 aggregateChannelHealth 以便单测;另新增 RequestHealthSnapshot
按需重算入口(维护循环消费,满则丢弃由下一轮兜底),供渠道测试/重置健康度接入。
健康上报是 fire-and-forget,重算前等 500ms 让 worker 落完 Redis。
2026-08-27 21:59:43 +08:00
chengqian 3035fa118c fix(dispatch): 修复 HMGET 判空失效导致冷渠道健康分被读成 0
ReadRuntime 用 `!vals[0].IsNil()` 判断 HMGET 结果是否存在,但 gredis 把 Redis
nil 数组元素包装成非 nil 空 gvar(IsNil() 恒为 false、Float64() 静默返回 0),
导致所有从未被真实流量访问过的渠道×模型被读成健康 0 分而非默认满分 1.0:管理
后台渠道健康度全线坍缩(如某渠道 (1.0+0)/2 → 0.5²×100=25 长期不动),调度侧
healthFactor 同样归零,冷模型路由权重被压死。

GET/HGET 单值回复的 IsNil() 正常,仅数组回复有此坑;仓库内 HMGET 调用点仅
ReadRuntime 与 readBreaker 两处,后者因默认值 BreakerClosed 恰为零值而侥幸
无害,一并改为按字符串判空。

- ReadRuntime:TrimSpace 判空 + ParseFloat 值域校验(succ 取 0<f<=1,EWMA
  由正数衰减而来不会精确到达 0,精确 0 视为异常数据)
- 回归测试:key 不存在须回落默认值、空串/非法值/精确 0 防御
- 通用规则写入 goframe-conventions.md 框架使用错误记录

同时补齐探测与健康分的可观测性(本次排查绕行三次的直接原因是全链路静默):

- [ChannelProbe] 探测全流程:轮次起止、模型与上游映射、结果、是否上报健康
- [ChannelHealth] 健康分变化:EWMA 变化点(Outcome.Probe 区分探测/真实流量
  来源)、快照落盘含各模型 succ 明细、维护轮次覆盖摘要
- 快照落库失败由 Debug 升为 Warning(此前静默,健康分冻结无从定位)
- 探测目标不在调度目录时告警(该场景健康分不落盘且渠道不参与调度)
- 变化类日志按「分数实际移动」触发,稳态降为 Debug,避免生产流量刷屏
2026-08-27 21:59:42 +08:00
chengqian d2e3794e3a fix(channel):修复渠道健康分数一直下降的问题 2026-08-26 16:49:25 +08:00
chengqian 330d02f19d feat(channel):渠道详情页显示模型监控信息 2026-08-19 18:34:21 +08:00
qian c7d15d82a4 improve(admin):优化管理功能搜索条件 2026-08-04 22:50:57 +08:00
Qian 2ef5a40c26 新的调度方式 (#14)
重构模型渠道调度系统
2026-08-01 22:55:08 +08:00