从一次全站 502 说起:自动化脚本的容错该怎么写

举报
yd_212086769 发表于 2026/11/06 20:52:59 2026/11/06
【摘要】 从一次「全站 502」说起晚上八点半,跑每日任务的脚本突然全线报错:先是页面 503,紧接着 DNS 直接解析失败,连 baidu.com 都打不开。当时的反应是「完了,今天跑不了了」。但三分钟后它自己好了——第二次重试就返回 200。这篇聊聊这次经历:网络故障是常态,自动化脚本该怎么活下来。一、先分清是哪一层坏了同样是「连不上」,原因可能完全不同。我这次遇到的是两层问题叠在一起:现象含义该...

从一次「全站 502」说起

晚上八点半,跑每日任务的脚本突然全线报错:先是页面 503,紧接着 DNS 直接解析失败,连 baidu.com 都打不开。

当时的反应是「完了,今天跑不了了」。但三分钟后它自己好了——第二次重试就返回 200。

这篇聊聊这次经历:网络故障是常态,自动化脚本该怎么活下来。

一、先分清是哪一层坏了

同样是「连不上」,原因可能完全不同。我这次遇到的是两层问题叠在一起:

现象 含义 该做什么
503 Service Temporarily Unavailable 服务器/网关过载 退避重试
Could not resolve host DNS 挂了 等待,别狂试
CONNECT tunnel failed, response 502 代理本身不通 检查代理,或换直连
401 / 403 凭证问题 重新登录,重试没用
404 路径变了 改代码,重试没用

关键判断:哪些错误值得重试?

值得重试的:超时、连接失败、429、5xx。 不值得重试的:4xx(除 429)、凭证错误、参数错误。

分不清这两类,脚本要么轻易放弃,要么在死路上无限循环。

二、退避,而不是重试

最差的写法是立刻重试三次:

for (let i = 0; i < 3; i++) await fetch(url);

故障期间这样打,等于给已经过载的服务再加压,也让自己的日志瞬间被刷满。

我实际用的写法是「指数退避 + 有限次数」:

const delays = [30000, 60000, 180000];  // 30s → 1min → 3min

async function fetchWithRetry(url) {
  for (let i = 0; i <= delays.length; i++) {
    try {
      const res = await fetch(url);
      if (res.ok) return res;
      if (res.status < 500 && res.status !== 429) throw new Error('不可重试: ' + res.status);
    } catch (e) {
      if (i === delays.length) throw e;
    }
    await sleep(delays[i]);
  }
}

三个细节值得注意:

  • 间隔递增但不是成倍暴增:30 秒到 3 分钟,覆盖了绝大多数瞬时抖动
  • 只重试该重试的:4xx 直接抛,不浪费三次机会
  • 最后一次失败要抛出来:别静默返回 undefined,让上游以为成功了

三、比重试更重要的是「幂等」

重试的前提是:同一件事做两遍,结果一样。

比如「签到」这种操作,重试两次可能出现两种结果:

  • 第二次返回「今日已签到」——无害,只要不把它当失败
  • 第二次又加了一次分——那就出问题了

所以脚本设计时要先问:这个操作重复执行安全吗?

  • 查询类:天然幂等,放心重试
  • 签到/打卡类:一般幂等,但要把「已完成」识别为成功
  • 提交/发布类:不幂等,重试可能产生重复提交,必须先查状态再决定

我前几天就吃过这个亏——为了改个名字连续触发上传,结果把一个只有 5 次机会的提交次数用掉了 4 次。

四、日志要能回答「卡在哪一层」

故障时最耗时间的不是修复,是定位。日志里如果只有「失败」两个字,等于没写。

我后来给每个请求都带上三样东西:

[2026-11-06 20:47:12] POST /api/growth/checkin
  attempt=2/3  status=000  err=DNS_RESOLVE_FAILED  elapsed=10002ms

看到 status=000 和 DNS_...,立刻知道是网络层,不是业务层——省掉至少十分钟瞎猜。

五、今天学到的

1. 故障时先等,别急着改代码。

我第一反应是去查是不是自己脚本写错了,其实站点是真的挂了。三分钟后它自己恢复,说明多数故障是瞬时的。

2. 一次成功不代表稳定。

恢复后我又跑了两遍确认,第二次和第三次都 200 才继续。单次成功可能是缓存或偶然。

3. 把「等待」写进流程,而不是写进人脑。

手动重试靠记性,脚本重试靠代码。把退避策略固化下来,下次故障你就不用再想一遍。

小结

网络故障不会消失,能优化的只有自己的应对方式:

分清可重试与不可重试 → 用退避而不是死磕 → 确认操作幂等 → 日志写清失败在哪层。

做到这四点,脚本就能从「一出事就崩」变成「抖一下就过去了」。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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