对外提供支付回调和订单创建接口时,如何设计幂等,避免超时重试造成重复数据?
我的判断
幂等要让同一个业务意图有稳定键,并把“占用幂等键”和业务写入放进同一事务,重复请求返回第一次结果。
订单创建会要求客户端生成 requestId,服务端唯一约束 (tenant_id, request_id)。第一次请求创建订单并保存响应摘要;超时重试命中同一键时查询原订单返回,而不是再创建一笔。只在 Redis SETNX 挡一下不够,key 过期或故障后仍可能重复。
支付回调则优先使用渠道流水号作为幂等键,在数据库事务中插入回调记录并做订单状态条件更新:
UPDATE orders
SET status = "PAID"
WHERE id = ? AND status = "PENDING";
重复 PAID 回调返回成功;若订单已取消,则进入人工/补偿规则,不能简单当幂等成功吞掉。幂等还要校验同一 key 的请求参数摘要,防止客户端误用同一个 requestId 提交不同金额。
记录会按业务最长重试窗口保留,指标包含重复率、参数冲突和处理中的超时。幂等不是“所有重复都忽略”,而是相同意图得到相同可解释结果。