订单超时关闭十分钟后支付回调才到,状态从 CLOSED 直接改成 PAID,库存没有回补,用户付了钱却发不了货。乍看像缓存或者权限的锅,追下去往往不是。
UPDATE `order` SET status = 'PAID' WHERE order_no = '20260301015' AND status = 'PENDING_PAY'; # 影响行数为 0 说明状态已变 走退款流程
追下去是这么回事:回调处理只判断订单存不存在,没有校验当前状态能不能转到 PAID。状态机里 CLOSED 是终态,代码里没有对应的拦截分支。
「状态机终态校验」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。接口问题先分清是没发出去、发出去了没收到,还是收到了处理失败。
偶发问题先统计频率,一小时几次和一天一次,查法完全不同。
具体做法是,状态流转收拢到一个方法 用白名单表约束允许的迁移;CLOSED 收到的支付回调直接退款 不改状态;更新语句带 where status=原状态 防止并发覆盖;回调日志记录订单原状态和流转结果。
验收就看一点,对已关闭订单再发回调 状态保持 CLOSED 并触发退款 日志里有状态不允许的提示。
