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