Files
junhong_cmp_fiber/openspec/changes/fix-package-activation-starvation/proposal.md
break 5e552d99bc 收口审计治理与套餐任务进展
Constraint: 在线热修前必须保存当前迭代分支全部有效代码进展
Confidence: medium
Scope-risk: broad
Directive: 后续修改需保持审计事件与业务事务边界一致
Tested: git diff --cached --check
Not-tested: 未运行全量测试,提交用于切换分支前保存既有工作
2026-08-05 14:30:54 +08:00

3.5 KiB
Raw Blame History

Why

功能 IDfeature-505-package-activation-recovery

生产环境已第二次出现“原主套餐已过期、队首待生效主套餐仍停留在 status=0”的问题。只读数据证明旧孤儿扫描每轮固定读取的 100 条记录全部仍有占位主套餐,真实孤儿因此永久无法进入恢复窗口;七月迭代分支需要按其现有同步接续能力和卡观测 Outbox 架构消除同类缺陷,避免未来覆盖发布后继续复现。

What Changes

  • 将孤儿恢复改为由 PostgreSQL 在限流前完成“每个载体只选队首套餐”和“排除仍有 status IN (1,2) 占位主套餐”的筛选,避免固定前 100 条造成永久饥饿,并删除逐条占位检查的 N+1 查询。
  • 七月分支的过期接续不再投递 package:queue:activation Asynq 任务:旧套餐过期事务提交后,直接调用现有 ActivateNextPendingMainPackage 推进队首套餐。
  • 孤儿恢复同样直接调用 ActivateNextPendingMainPackage,复用载体级 Redis 锁、状态幂等、购买条款快照和激活事务。
  • 套餐激活事务继续原子写入现有 card.observation.series.requested Outbox由七月分支公共 Outbox 可靠驱动后续实名、流量和网络观测;不新增第二种套餐激活事件。
  • 收紧结果日志:只有实际推进套餐状态时记录激活成功,锁冲突、占位阻塞、等待实名和幂等跳过分别记录稳定原因。
  • 按用户明确要求,本 Change 不新增、修改或运行自动化测试;使用全量构建、只读 SQL、查询计划和运行日志完成验证。

Capabilities

New Capabilities

无。

Modified Capabilities

  • package-queue-activation:将七月迭代的过期接续与孤儿恢复收口为同步应用调用,并补充真实孤儿公平扫描和既有卡观测 Outbox 一致性要求。

Impact

  • 适用分支:仅 Iteration/7-11,按当前分支的同步接续与卡观测 Outbox 架构独立实施。
  • 架构通道:主通道为套餐生命周期复杂写,沿用 Polling Handler → Package Activation Service → GORM transaction;辅助通道为 PostgreSQL 候选查询、Redis 载体锁和既有卡观测 Outbox。完整边界只覆盖“旧套餐过期后接续队首套餐及孤儿恢复”不迁移购买、实名、流量、退款和停复机用例。
  • 主要代码internal/polling/package_activation_handler.go、必要时最小调整 internal/service/package/activation_service.go 的结果日志;复用现有 internal/infrastructure/cardobservation/series_event.go 和公共 Outbox 装配。
  • 数据库:不新增表、字段、索引或迁移;只调整现有 tb_package_usage 查询和调用顺序。
  • API/前端无接口、DTO、路由和前端改动。
  • 依赖:不新增依赖,继续使用 GORM、PostgreSQL、Redis、Zap 及七月分支已有 Outbox。
  • 性能:孤儿扫描从“最多 100 条候选 + 最多 100 次占位查询”收敛为一次数据库候选查询和最多 100 次有业务意义的同步激活调用;使用 EXPLAIN (ANALYZE, BUFFERS) 验证查询成本。
  • 审计与可靠性Audit Event N/A系统自动生命周期推进tb_package_usage 是状态权威事实Integration Log N/A本修复不新增外呼复用现有 card.observation.series.requested Outbox不新增事件类型。
  • 验证:不写自动化测试;执行 gofmt、现有静态检查、go build ./...、只读 SQL、查询计划和日志核验。