订单超时关闭十分钟后支付回调才到,状态从 CLOSED 直接改成 PAID,库存没有回补,用户付了钱却发不了货。乍看像缓存或者权限的锅,追下去往往不是。

UPDATE `order` SET status = 'PAID'
WHERE order_no = '20260301015' AND status = 'PENDING_PAY';
# 影响行数为 0 说明状态已变 走退款流程

追下去是这么回事:回调处理只判断订单存不存在,没有校验当前状态能不能转到 PAID。状态机里 CLOSED 是终态,代码里没有对应的拦截分支。

「状态机终态校验」相关的日志我一般连着看前后五分钟,单看一条报错经常判断不出是哪一步失败。接口问题先分清是没发出去、发出去了没收到,还是收到了处理失败。

偶发问题先统计频率,一小时几次和一天一次,查法完全不同。

具体做法是,状态流转收拢到一个方法 用白名单表约束允许的迁移;CLOSED 收到的支付回调直接退款 不改状态;更新语句带 where status=原状态 防止并发覆盖;回调日志记录订单原状态和流转结果。

验收就看一点,对已关闭订单再发回调 状态保持 CLOSED 并触发退款 日志里有状态不允许的提示。

作者 9823189