自动化里的幂等设计:为什么重试不能“再来一次”
【摘要】 重试不是简单再来一次。本文从幂等键、唯一约束、状态机前置校验三种实现出发,讲清哪些失败可重试、如何退避限流,以及浏览器自动化里判断状态、复查结果、记录业务主键的幂等实践。
自动化里的幂等设计:为什么重试不能“再来一次”
引子
网络抖动、接口超时、页面卡顿,自动化脚本几乎一定会遇到失败。直觉做法是“失败了重试一次”,但很多重复数据、重复扣款、重复提交,恰恰是重试造成的。要安全地重试,前提是操作本身幂等。
一、什么是幂等
幂等(Idempotency)指:同一个操作执行一次和执行多次,对系统最终状态的影响相同。注意是最终状态相同,不是“每次都返回相同响应”。
- 查询:天然幂等;
- 设置状态(把状态改为“已完成”):幂等;
- 自增、追加、创建订单:不幂等,重复执行会产生多条数据。
二、重试为什么会出事
典型场景:客户端发起创建请求,服务端处理成功但响应超时。客户端不知道成功与否,重试一次,于是产生两条记录。
POST /api/orders → 超时(实际已创建)
POST /api/orders (重试) → 又创建一条
问题不在重试本身,而在请求没有唯一标识,服务端无法判断这是“新请求”还是“同一请求的重发”。
三、三种常见的幂等实现
1. 幂等键(Idempotency Key)
客户端为每次业务操作生成唯一键,随请求发送;服务端记录键与结果,重复键直接返回首次结果。
headers = {"Idempotency-Key": request_id}
要点:键必须在重试之间保持不变,不能每次重试重新生成。
2. 唯一约束 / 去重表
数据库层用唯一索引兜底,例如订单号、业务流水号唯一。即使并发重试,也只会成功一条:
CREATE UNIQUE INDEX uk_order_no ON orders(order_no);
插入冲突时捕获唯一键异常,转为“已存在”的成功语义。
3. 状态机前置校验
执行前先判断当前状态,只有处于允许的前置状态才执行:
if state != "待提交":
return already_done
state = "提交中"
配合状态流转的原子更新(UPDATE ... WHERE state='待提交'),可以避免并发重复执行。
四、重试策略:不是所有失败都该重试
重试前先分类:
- 可重试:超时、连接重置、429/5xx;
- 不可重试:400 参数错误、401/403 鉴权失败、业务校验失败。
可重试的场景也要有退避,避免把下游打垮:
for attempt in range(3):
try:
return call()
except RetryableError:
time.sleep(2 ** attempt + random.random())
同时设置总超时与最大次数,防止无限重试。
五、浏览器自动化里的幂等
页面操作同样需要幂等思维:
- 点击前判断状态:按钮已是“已提交/已完成”就不再点;
- 提交后确认结果:等待成功提示或接口 200,而不是凭“点到了”判断;
- 重试前先复查:失败时先查询是否其实已成功(例如列表中已存在),再决定是否重试;
- 记录业务主键:把返回的 ID 落盘,后续用 ID 查询而不是重复创建。
if page.locator(".status-tag").inner_text() == "已完成":
return True
submit_once()
wait_for_success()
一个实用技巧:把“操作 + 结果确认”封装成函数,函数内部负责幂等判断,调用方只关心最终状态。
六、小结
安全重试的三条底线:
- 请求可识别:用幂等键或业务唯一号标识同一次操作;
- 服务可兜底:唯一约束与状态机原子更新防止重复落库;
- 重试有边界:只重试可重试错误,带退避与上限,失败前先复查结果。
做到这三点,“重试”才从风险操作变成可靠性手段。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)