自动化里的幂等设计:为什么重试不能“再来一次”

举报
yd_296261293 发表于 2026/11/06 14:10:03 2026/11/06
【摘要】 重试不是简单再来一次。本文从幂等键、唯一约束、状态机前置校验三种实现出发,讲清哪些失败可重试、如何退避限流,以及浏览器自动化里判断状态、复查结果、记录业务主键的幂等实践。

自动化里的幂等设计:为什么重试不能“再来一次”

引子

网络抖动、接口超时、页面卡顿,自动化脚本几乎一定会遇到失败。直觉做法是“失败了重试一次”,但很多重复数据、重复扣款、重复提交,恰恰是重试造成的。要安全地重试,前提是操作本身幂等。

一、什么是幂等

幂等(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())

同时设置总超时与最大次数,防止无限重试。

五、浏览器自动化里的幂等

页面操作同样需要幂等思维:

  1. 点击前判断状态:按钮已是“已提交/已完成”就不再点;
  2. 提交后确认结果:等待成功提示或接口 200,而不是凭“点到了”判断;
  3. 重试前先复查:失败时先查询是否其实已成功(例如列表中已存在),再决定是否重试;
  4. 记录业务主键:把返回的 ID 落盘,后续用 ID 查询而不是重复创建。
if page.locator(".status-tag").inner_text() == "已完成":
    return True
submit_once()
wait_for_success()

一个实用技巧:把“操作 + 结果确认”封装成函数,函数内部负责幂等判断,调用方只关心最终状态。

六、小结

安全重试的三条底线:

  • 请求可识别:用幂等键或业务唯一号标识同一次操作;
  • 服务可兜底:唯一约束与状态机原子更新防止重复落库;
  • 重试有边界:只重试可重试错误,带退避与上限,失败前先复查结果。

做到这三点,“重试”才从风险操作变成可靠性手段。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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