Files
junhong_cmp_fiber/openspec/specs/traffic-daily-buffer/spec.md
huang cebcada950
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m16s
refactor: 流量系统重构 — 增量累加算法 + 日粒度缓冲 + 旧详单清理
核心改造:
- 增量算法:流量计算从覆盖式改为增量累加(gateway - lastReading),支持上游运营商重置检测
- 日流量缓冲:insertDataUsageRecord 改为 Redis INCRBYFLOAT,每日凌晨落盘到 tb_card_daily_usage
- 运营商:新增 data_reset_day 字段(联通=27,其余=1)
- IoT卡:新增 last_gateway_reading_mb 字段存储上次网关读数
- 查询层:新建 TrafficQueryService 合并 Redis(今日)+ DB(历史)数据源
- 清理:删除 DataUsageRecord model/store,移除 polling_handler 旧引用

迁移:000094-000097(carrier字段、iot_card字段、数据初始化、日流量表)
2026-03-30 09:59:30 +08:00

1.7 KiB
Raw Blame History

ADDED Requirements

Requirement: 流量增量写入 Redis 缓冲

轮询检测到流量增量 > 0 时,系统 SHALL 使用 INCRBYFLOAT 将增量写入 Redis key格式 traffic:daily:{card_id}:{YYYY-MM-DD}TTL 48 小时。增量 <= 0 时 SHALL NOT 写入。直接替换旧的 insertDataUsageRecord() 写 DB 路径,不双写。

Scenario: 有流量增量时写 Redis

  • WHEN 轮询检测到卡 ID=100 今日流量增量为 5.2 MB
  • THEN 系统 SHALL 执行 INCRBYFLOAT traffic:daily:100:2026-03-28 5.2,并设置 48h TTL

Scenario: 无流量增量时跳过

  • WHEN 轮询检测到流量增量 <= 0
  • THEN 系统 SHALL NOT 执行任何 Redis 或 DB 写入

Requirement: 每日落盘定时任务

系统 SHALL 每天凌晨 2 点Asia/Shanghai通过 Asynq Scheduler 触发落盘任务。

Scenario: 正常落盘(分批处理)

  • WHEN 凌晨 2 点落盘任务执行
  • THEN 系统 SHALL 分批 SCAN 所有 traffic:daily:*:{昨日} key每批 COUNT 500
  • AND 分批 UPSERT 到 tb_card_daily_usage(每批 200 条,覆盖语义保证幂等:ON CONFLICT DO UPDATE SET usage_mb = EXCLUDED.usage_mb
  • AND 分批 Pipeline 删除已落盘的 Redis key
  • AND 记录日志:落盘条数、耗时

Scenario: 落盘失败重试

  • WHEN 落盘任务执行失败
  • THEN Asynq SHALL 自动重试MaxRetry=3超时 5 分钟Redis key 因 48h TTL 仍可用
  • AND 因 UPSERT 使用覆盖语义,重试时不会导致数据翻倍

Requirement: tb_card_daily_usage 表结构

usage_mb 字段 SHALL 使用 NUMERIC(12,2) 类型(匹配 Redis INCRBYFLOAT 的浮点精度和现有 current_month_usage_mbdecimal(10,2) 类型),不使用 BIGINT。