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>
7.9 KiB
7.9 KiB
0. 前置
- 0.1 经维护者确认,归档
rebuild-card-traffic-metering-and-stop-resume(9.2–9.5 灰度与切换水位验证作废)与add-tiered-polling-and-pre-activation-settlement,确认openspec/specs/card-traffic-metering/spec.md存在且包含本 Change 修改与删除的要求。
1. 迁移与模型
- 1.1 新增成对迁移:采集记录表(按
observed_at按月分区,字段见方案 7.1,索引(iot_card_id, observed_at DESC)、observation_id),预建当月与下月分区;down 删除。 - 1.2 新增成对迁移:冲正流水表(字段见方案第 11 节);down 删除。
- 1.3 新增成对迁移:
tb_iot_card增加待建起点标记,up 内把全部卡置位;down 删除该列。 - 1.4 新增成对迁移:套餐日用量
(package_usage_id, date)唯一索引,建前合并已有重复行;down 删除索引。(测试库已有唯一索引idx_package_usage_daily_record_unique且无重复行,无需新迁移) - 1.5 新增对应 model;采集记录分区的按月新建与过期整月删除任务(保留 90 天)。
2. 读数有效性
- 2.1
internal/gateway/models.go:流量查询结果的已用流量改为零值表示"没值"的类型,区分 null/空/无法解析/缺字段与 0;其他使用FlexFloat的字段不变。 - 2.2
internal/task/polling_carddata_handler.go:按方案第 3 节把结果分为有效、失败、限流、响应无效、无读数、读数无效。 - 2.3
internal/domain/cardflow/rules.go:ValidReading放宽为有限且 ≥ 0;isStale去掉ThisMonthBeforeResetMax > 0条件;同步注释。
3. 采集队列
- 3.1 新增队列组件:key
traffic:queue:{card_id},Lua 原子完成跨天清空、过期丢弃、按采集时间插入去重、保留最后 N 个、设置过期(跨天清空开启时为次日 01:00 上海时间,关闭时为最长点龄后),返回队列与新点是否在队尾。 - 3.2 写入判断:新点在队尾、队列满 N、相邻两点不下降(容差内算持平);返回写入或不写原因(队列未满、读数下降、乱序)。
- 3.3 系统配置注册
traffic.queue.size(默认 3,最小 2)、traffic.queue.clear_on_new_day(默认 true)、traffic.queue.max_point_age_hours(默认 72)、traffic.queue.drop_tolerance_mb(默认 1),读法与package.silence.enabled相同(带短缓存)。 - 3.4 轮询配置保存与启用时、队列长度或跨天清空开关修改时,校验启用中轮询配置的流量采集间隔上限;停用配置不校验。
4. 有套餐判断与观测写入
- 4.1 package 服务新增"采集时刻有效套餐"查询(状态生效中/已用完/已过期、
activated_at ≤ observed_at或为空、expires_at为空或晚于采集时间、未退款,卡没有时看当前绑定设备),供观测与扣减共用。 - 4.2
traffic_calc_policy.go:hasActivePackageForCard改调 4.1;删除灰度名单与计量模式;删除pkg/config中TrafficCalc的模式与名单配置及部署变量。 - 4.3
traffic.go、traffic_flow.go:只在队列写入点进入快照;删除未切换分支、firstSwitch与切换水位读写;卡表基线算法不再产生扣费增量,last_gateway_reading_mb不再使用。 - 4.4 写入范围:有套餐读数 0 写快照、没套餐读数 0 不写;Δ 有套餐发事件(带
observed_at、observation_id),没套餐只记已结算。 - 4.5 待建起点:带标记的卡第一次写入时写快照、本月最大全部记为已结算、不发事件、清标记,采集记录判断为建起点。
- 4.6 观测事务内当天第一次写入时,调用 package 服务为采集时刻每个有效套餐确保当天日用量 0 行。
- 4.7 通道阈值判定只在写入点、读数 > 0 且未触发防旧值时调用;卡表本月用量对全部卡用本月最大快照覆盖;日流量对全部卡读快照。
- 4.8 采集记录:有套餐的卡每次采集写一条(含失败、读数 0、被拦下),字段按方案 7.1。
5. 其他读数来源
- 5.1 人工刷新过队列,接口返回本次读数、是否写入与原因;更新路由文档说明。
- 5.2 激活前结算过队列;未写入时用已有本月最大快照结算、不新写快照,采集记录判断为"激活前结算用已有快照";删除"未切换卡不做结算"的分支。
6. 换卡
- 6.1
internal/service/exchange:换卡完成事务内给新卡置待建起点标记;设备换货时给新设备当前绑定的每张卡置位;不调用运营商接口。
7. 扣减
- 7.1
internal/infrastructure/cardobservation/event.go:把observed_at、observation_id传给扣减;日流量缓冲 key 改用cardflow.ShanghaiDate(observed_at)。 - 7.2
DeductDataUsage按采集时刻调用 4.1 查套餐;排序、容量、超出承接与小数累积不变。 - 7.3 状态迁移只作用于当前生效中套餐;已用完、已过期只累加不改状态;停机判断仍按当前状态。
- 7.4 查不到套餐时写告警与跳过审计,事件按成功处理不重试。(没有套餐可挂审计资源,跳过只写带 metric 的告警日志)
- 7.5 采集早于套餐
last_reset_at的照扣在重置后周期,审计记录observed_at与last_reset_at。 - 7.6
updateDailyRecord改为 upsert(当天用量累加、累计用量覆盖),日期取采集时间上海日期;提供"确保当天日用量行"方法。
8. 冲正与后台接口
- 8.1 冲正用例:事务内
SELECT ... FOR UPDATE锁套餐行,按当前值加减,结果 < 0 拒绝;写流水、更新已用量、按阈值重算状态(已过期/已失效只改已用量);写审计package_usage.adjust_traffic;提交后调用evaluator.EvaluateAndAct。 - 8.2 后台接口:冲正(必填原因、可选关联采集与事件)、冲正流水查询、采集记录按卡与时间范围查询;权限与现有套餐管理一致。(原"修改资产套餐已用量"接口改为按差额写冲正流水)
- 8.3 同步
cmd/api/docs.go、cmd/gendocs/main.go,运行go run cmd/gendocs/main.go。
9. 告警
- 9.1 开启轮询且有套餐的卡一整天没有已写入;开启轮询的卡待建起点超过 1 天;单卡读数下降占比过高或全局拦截率突增;乱序突增;重置日防旧值命中数统计。不轮询的卡不告警。
10. 构建与测试环境验证
- 10.1 对变更 Go 文件执行
gofmt -w,运行go build ./cmd/api ./cmd/worker、openspec validate add-card-traffic-queue-and-observed-deduction --strict。 - 10.2 按 ENG-TEST-001 在测试环境执行迁移 up/down/up,核对新表、分区、唯一索引与全部卡待建起点标记。
- 10.3 用构造的测试卡(参照
cmd/zz_tmp_cardflow_verify)逐项核对:正常累加、中间点暴涨被拦、清零前后不混写、容差内回退写入、乱序不写、跨天清空、读数 0 有/没套餐的写入范围、null 与缺字段不入队。 - 10.4 重置日:配置重置日 1 与 27 各一张卡,核对重置日全天防旧值、比较基准为 0 时当天按 0 计且次日如实写入、重置日早上的旧数不更新前一天快照。
- 10.5 全量切换与换卡:切换后第一次写入只建起点不扣费;换卡新卡写入 55 建起点、58 扣 3;起点读数异常不被当起点。
- 10.6 扣减:已用完在有效期内的套餐承接超出;采集后到期照扣、状态不被改回已用完;采集后退款跳过不重试;套餐日用量按采集日期 upsert、没扣写 0。
- 10.7 冲正:退回后状态恢复并交给停复机判断;结果为负被拒;与扣减并发不覆盖;因未实名停机的卡冲正后不复机。
- 10.8 人工刷新返回写入结果;激活前结算未写入时用已有快照结算;采集记录可从扣费审计经采集 ID 追到;轮询配置间隔校验只拦启用中配置。