98 lines
5.9 KiB
Markdown
98 lines
5.9 KiB
Markdown
---
|
|
name: 修复中等与轻微问题6项
|
|
overview: 按二次审查报告修复 6 个问题:M1(退款推送 RefundStatus 空串误回收)、M2(发货校验失败返回成功应答吞资损线索)、M5(补偿任务 Failed 被回调重置)、M14(衣物失败回退与删除并发漏退)、M10(refresh-token access_token 文档矛盾)、M13(Outfit.Public 并发语义冲突)。限流(M11)与上传防护(M12)本次不修复。
|
|
todos:
|
|
- id: fix-xpay-notify
|
|
content: 修复虚拟支付推送链路:新增 XPayRefundStatusSuccess 常量,handleRefundNotify 改白名单判断,handleGoodsDeliver 五个校验失败分支返回 70009 触发微信重试
|
|
status: completed
|
|
- id: fix-benefit-reset
|
|
content: 修复补偿任务重置:BenefitGrantTaskReset 保留 retry_count,失败任务增加 5 分钟冷却期后才允许回调重新触发
|
|
status: completed
|
|
- id: fix-clothes-refund-tx
|
|
content: 修复衣物回退漏退:markProcessFailed 重写为行锁单事务,删除 refundIfExists 与 ClothesMarkProcessFailedIfNotFailed
|
|
status: completed
|
|
- id: fix-outfit-public-lock
|
|
content: 修复穿搭公开竞态:redismodel 新增 KeyLockOutfitPublic,OutfitService.Public 全流程加 Redis 锁串行化
|
|
status: completed
|
|
- id: sync-docs
|
|
content: 同步文档:README 修正 refresh-token access_token 为必填,审查报告 M1/M2/M5/M10/M13/M14 标注已修复
|
|
status: completed
|
|
dependencies:
|
|
- fix-xpay-notify
|
|
- fix-benefit-reset
|
|
- fix-clothes-refund-tx
|
|
- fix-outfit-public-lock
|
|
- id: verify
|
|
content: 验证 go build 与 go test 通过,read_lints 无新增告警
|
|
status: completed
|
|
dependencies:
|
|
- sync-docs
|
|
---
|
|
|
|
## 用户需求
|
|
|
|
根据二次代码审查报告,修复用户确认的 6 个问题(最新调整:限流缺失 M11、上传防护 M12 暂不修复):
|
|
|
|
1. **M1 退款推送误回收**:`RefundStatus` 字段为空串或未知值时被误判为「退款成功」并回收权益,修复为仅当明确等于 `SUCCESS` 才回退
|
|
2. **M2 发货校验失败静默**:发货推送本地校验失败(订单不存在/渠道不符/道具不符/金额不符/环境不符)返回成功应答,微信不重试且资损线索被吞掉,修复为返回失败应答触发重试
|
|
3. **M5 补偿任务重试上限失效**:失败任务被支付回调重置(retry_count 清零),绕过重试上限与人工介入机制
|
|
4. **M14 衣物额度漏退窗口**:异步处理失败回退与用户删除并发时,可能两个「应回退」事件叠加却零回退,用户损失额度
|
|
5. **M10 refresh-token 文档矛盾**:README 标注 access_token 为可选,但代码要求必填,统一为必填
|
|
6. **M13 穿搭公开并发语义冲突**:并发公开时,一个请求回退公开态后,另一请求已误报成功
|
|
|
|
## 约束
|
|
|
|
- 保持现有代码风格(slog 结构化日志、errcode 错误码、Redis fail-open 降级)
|
|
- 修复后 `go build ./...` 与 `go test ./pkg/wechat/` 必须通过,read_lints 无新增告警
|
|
- 不修改普通微信支付 V3 回调链路;M3/M4/M6-M9/M11/M12/M15 及未点名问题不在本次范围
|
|
|
|
## 技术方案
|
|
|
|
### 1. M1 + M2:虚拟支付推送链路修复
|
|
|
|
**M1 退款推送白名单**
|
|
|
|
- `pkg/wechat/virtualpay.go`:新增常量 `XPayRefundStatusSuccess = "SUCCESS"`
|
|
- `internal/service/virtualpay.go` 的 `handleRefundNotify`:改为 `if refund.RefundStatus != wechat.XPayRefundStatusSuccess { slog.WarnContext(...); return nil }`,仅成功状态走 `settleRefundSuccess`;订单不存在分支保持 `return nil`
|
|
|
|
**M2 发货校验失败应答**
|
|
|
|
- `handleGoodsDeliver` 中以下五个分支由 `return nil` 改为 `return errcode.OrderRealityCheckFailed`(70009 已存在),使 `XPayNotify` 回 `ErrCode:1` 让微信重试:
|
|
- 订单不存在
|
|
- `pay_channel != PayChannelVirtual`
|
|
- 道具 ID 不匹配
|
|
- 实付金额不匹配
|
|
- 环境不匹配
|
|
- 锁竞争失败分支保持 `return nil`(并发回调交由持锁者处理,防重试风暴)
|
|
|
|
### 2. M5:补偿任务重置保护
|
|
|
|
- `internal/mysqldao/benefit_grant_task.go` 的 `BenefitGrantTaskReset`:删除 `retry_count: 0`,保留原重试计数
|
|
- `internal/service/order.go` 的 `grantBenefitIdempotent` Failed 分支:新增冷却常量 `benefitRetryCooldownSeconds = 300`;当 `nowUnix()-existing.UpdatedAt < 300` 时仅打告警跳过,冷却期外才 Reset + executeGrant,恢复重试上限与人工介入机制
|
|
|
|
### 3. M14:衣物处理失败回退事务化
|
|
|
|
- `internal/service/clothes.go` 重写 `markProcessFailed` 为单事务(复用 `DeleteByUUID` 的 FOR UPDATE + 回退模式):
|
|
|
|
1. `tx.Clauses(clause.Locking{Strength: "UPDATE"})` 按 `clothes_uuid` 查衣物;不存在/已软删(RecordNotFound)或已是失败态则提交并跳过
|
|
2. 置 `image_process_status=5` + `fail_reason`
|
|
3. 同事务回退额度:条件更新 `used - 1`(used>=1),回读真实值,写回退流水(Reason="衣物处理失败回退",OrderNo=流水 UUID 兜底)
|
|
|
|
- 删除 `refundIfExists` 方法与 `internal/mysqldao/clothes.go` 的 `ClothesMarkProcessFailedIfNotFailed`(已确认仅此一处调用)
|
|
- `DeleteByUUID` 保持不变:行锁读到失败态即跳过回退,与失败事务通过行锁互斥,两路径恰好回退一次
|
|
|
|
### 4. M13:穿搭公开加 Redis 锁
|
|
|
|
- `internal/redismodel/lock.go`:新增 `KeyLockOutfitPublic = RedisPrefix + "lock:outfit:public:%s"`(outfit_uuid)
|
|
- `internal/service/outfit.go` 的 `Public`:进入后先 `redisdao.TryLock(fmtLockKey(KeyLockOutfitPublic, request.OutfitUUID), 10s)`,失败返回 `errcode.TooManyRequests`;成功 `defer` 解锁;锁内保留现有「条件公开 → 扣额 → 失败回退」流程,串行化后并发请求语义正确
|
|
|
|
### 5. M10 + 文档同步
|
|
|
|
- `README.md` 686 行:access_token 由「否(可选,向前兼容)」改为「是(必填)」,说明缺少返回 10000
|
|
- `docs/代码审查报告-二次check.md`:M1/M2/M5/M10/M13/M14 标题后标注「已修复」及一行修复说明;M11/M12 保持未修复状态
|
|
|
|
### 验证
|
|
|
|
- `go build ./...` 全量编译通过
|
|
- `go test ./pkg/wechat/` 通过
|
|
- `read_lints` 检查修改文件无新增告警 |