All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m27s
- 每卡 Redis 采集队列(默认 N=3、跨天清空、回退容差 1 MB),攒满且不下降才写最后一个点 - 测试环境全量切换日快照计量,下线灰度名单、切换水位与卡表基线扣费;全部卡置待建起点 - 读数区分没给值与 0;有套餐的卡读数 0 也写快照与日用量 0 行;重置日比较基准为 0 照常防旧值 - 新增采集记录(按月分区保留 90 天)、人工冲正流水与后台接口、采集告警 - 扣减按采集时刻有效套餐查找,只对生效中套餐做状态迁移,查不到套餐按成功跳过 - 换货新卡(新设备下的卡)打待建起点;采集间隔上限只校验启用中的轮询配置 Change: add-card-traffic-queue-and-observed-deduction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.8 KiB
5.8 KiB
Why
rebuild-card-traffic-metering-and-stop-resume 已把计量改为日快照 + 本月最大值 − 已结算,解决了基线冻结、重置窗口重复扣的问题,但运营商单次异常读数仍直接写进快照(当天取最大值,暴涨会留下来);测试环境仍在灰度与卡表基线算法两条路径并存;扣减按扣费时刻的"生效中"套餐查找,采集与扣费对"有没有套餐"口径不一致,套餐用完到停机之间的用量收不到;扣错没有冲正通道,排查也缺少逐次采集记录。依据为 docs/卡流量采集写入与扣减技术方案.md(2026-10-28 修订,决策 T1–T25 及 10-28/29 补充决定)。
What Changes
- 运营商流量读数先判有效性:接口失败、限流、缺字段、
used为空/null/无法解析、负数、NaN/Inf 不入队、不写快照;有效读数为有限且 ≥ 0,Gateway 流量读数区分"没值"与 0。 - 新增每卡 Redis 采集队列(默认 N = 3,Lua 原子):按采集时间插入,跨天清空(可配,默认开)、丢弃过期点;新点在队尾、队列满 N 个点且相邻两点回退不超过容差(默认 1 MB)时才写最后一个点,否则不写并记录原因。轮询、人工刷新、激活前结算共用同一队列与规则;没有运营商流量推送。
- 队列配置(长度、跨天清空、最长点龄、回退容差)放系统配置,改了即生效;启用中的轮询配置流量采集间隔超过上限(开关开 24h ÷ (N+2),关
max_point_age_hours÷ (N+2))时拒绝保存或启用,停用的配置不校验。 - BREAKING(测试环境)一次性全量切换:所有卡走日快照 + 本月最大值 − 已结算;删除计量模式与灰度名单、第一次切换观测与切换水位,卡表基线算法不再产生扣费增量。迁移时全部卡打"待建起点"标记,切换后第一次写入只建起点不扣费。
- 写入范围:有套餐的卡读数为 0 也写日快照,每次采集写采集记录,每个有效套餐每天确保一行日用量(没扣写 0);没套餐的卡读数 > 0 才写快照,增量只记已结算、之后买套餐不补扣。
- 重置日照搬老系统,只认通道配置的重置日:重置日当天全天读数 > 比较基准 × 0.9 按 0 计;比较基准为 0 时不论重置日是几号都照常按 0 计;次日起不再判断;月末尾巴不补、不记回前一天。
- "有套餐"采集侧与扣费侧共用同一判断:采集时刻状态为生效中/已用完/已过期、已激活、未到期、未退款的套餐,卡自己没有时看绑定设备;已用完但在有效期内算有套餐。
- 扣减按采集时刻确定套餐:只对当前"生效中"的套餐做状态迁移;一个套餐都查不到时记审计并按成功跳过;采集后套餐被重置的扣在重置后的周期;套餐日用量改为 upsert,日期取采集时间的上海日期(含消费者日流量缓冲 key)。
- 换卡完成时新卡(设备换货时新设备下全部卡)打"待建起点"标记,第一次通过队列写入时建起点。
- 新增采集记录表(有套餐的卡每次采集一条,按月分区保留 90 天)与后台查询;新增人工冲正流水(锁套餐行、退回后不得为负、提交后走停复机判断)与后台接口。
- 新增告警:开启轮询且有套餐的卡一整天没写入、待建起点超过 1 天、队列拦截率异常、乱序突增、重置日防旧值命中数。
- 不在本 Change:自动对账(运营商 T+1 数据)、月末尾巴补算、对接日志/审计瘦身、跨套餐重置时的用量偏移、生产环境发布与回滚。
Capabilities
New Capabilities
package-traffic-deduction:按采集时刻确定扣减套餐、状态迁移范围、查不到套餐的处理、套餐日用量记录、人工冲正。
Modified Capabilities
card-traffic-metering:读数有效性与快照写入范围(读数 0 写入)、重置日防旧值比较基准为 0 的处理、增量对全部卡生效且"有套餐"改为共用口径、通道阈值只在写入点判断、展示对全部卡生效、激活前结算过队列;新增采集队列、队列配置与采集间隔校验、待建起点(全量切换与换卡)、采集记录、告警;删除切换水位与按扣减载体灰度切换。
Impact
- 前置:
rebuild-card-traffic-metering-and-stop-resume与add-tiered-polling-and-pre-activation-settlement须先归档(本 Change 修改它们新增的card-traffic-metering要求);前者剩余的灰度、切换水位验证作废。 - 数据库:新增采集记录表(按月分区)、冲正流水表;
tb_iot_card增加待建起点标记,迁移时全部卡置位;套餐日用量(package_usage_id, date)唯一索引;tb_card_flow_switch不再读写。均为新的成对迁移。 - 代码:
internal/gateway/models.go、internal/task/polling_carddata_handler.go、新增队列组件与系统配置项、internal/application/cardobservation/(traffic.go、traffic_flow.go、traffic_calc_policy.go)、internal/domain/cardflow/rules.go、internal/domain/cardobservation/traffic.go、internal/infrastructure/cardobservation/event.go、internal/service/package/usage_service.go、internal/service/exchange、人工刷新与激活前结算入口、轮询配置保存。 - 接口:人工刷新返回本次读数、是否写入与原因;新增采集记录查询、冲正接口;重新生成接口文档。
- 配置:删除
JUNHONG_TRAFFIC_CALC_MODE、JUNHONG_TRAFFIC_CALC_CARDS;新增系统配置traffic.queue.size、traffic.queue.clear_on_new_day、traffic.queue.max_point_age_hours、traffic.queue.drop_tolerance_mb。 - Redis:每卡一个队列 key(约 150 字节);测试环境为
noeviction。 - 范围:测试环境。