请求重试如何避免重复创建订单:幂等键、原子性与结果复用

举报
yd_210997990 发表于 2026/10/15 18:57:31 2026/10/15
【摘要】 以创建订单为例,说明幂等键、数据库唯一约束、事务与结果复用如何保障安全重试,并讨论外部副作用、崩溃恢复和去重记录的保留窗口。

本文讨论创建订单接口的安全重试,内容由 AI 辅助整理,示例用于说明设计思路,未声称经过生产压测。

超时不代表没有成功

客户端等待创建订单的响应超时,可能是请求没有到达,也可能是订单已经落库、响应却在网络中丢失。直接重发请求,可能创建两笔订单。服务端需要识别这次调用是原请求的重试,还是一次新的下单意图。

HTTP 方法幂等与业务请求幂等需要区分。HTTP 幂等关注相同请求重复执行后的预期效果,并不要求响应完全相同。PUT、DELETE 和安全方法具有幂等语义;POST 没有这一默认保证,但可以通过业务设计支持安全重试。

幂等键标识一次业务意图

客户端在首次提交前生成幂等键,同一次业务操作的所有重试复用该键;新一次下单使用新键。

POST /orders HTTP/1.1
Content-Type: application/json
Idempotency-Key: checkout-7d0b19af


{"sku":"book-001","quantity":1,"currency":"CNY"}

服务端应把键绑定到租户、接口和规范化后的请求参数。同一键第一次购买一本书,重试时却改成两本,应该拒绝并提示参数冲突。每次请求仍需独立检查身份与权限,不能凭知道某个键就读取其他用户的订单。

原子性与结果复用

“先查询、再插入”存在并发窗口:两个请求可能同时查到键不存在。可用数据库唯一约束,例如“租户+接口+幂等键”,争夺执行资格。已完成的请求返回已保存的订单编号和结果;处理中请求可以等待,或返回明确的处理中状态。

若先创建订单,再单独保存幂等结果,中间崩溃就会留下订单已存在、去重记录却缺失的窗口。单库场景可把幂等记录、订单与可复用结果放入同一事务。提交成功后,即使响应丢失,重试也能查回原结果。Redis 锁可以协调部分并发,但不能替代持久化事实。

支付、发消息等外部动作无法由一个本地事务全部覆盖。可以用事务消息表保存待执行事项,由后台重试;下游按稳定业务编号去重。处理中记录需要恢复机制,不能仅因超时就认定原操作失败并再次执行。

重试窗口与验证

去重记录应覆盖约定的重试窗口,但缓存过期不会让历史订单消失。超出窗口的旧请求可要求先查询原订单,或依靠保留更久的业务唯一编号防止重复创建。保留多久、处理中如何响应、失败结果能否重试,都应写入接口契约。

验证至少覆盖同键并发提交、提交后响应丢失、事务提交前后进程退出,以及同键不同参数。检查订单数量与返回订单编号,才能判断重试是否复用了原业务结果。

参考文档:

  • RFC 9110,第 9.2.2 节:Idempotent Methods。
  • Stripe 官方 API 文档:Idempotent requests。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。