十月补记:本文于 2026 年 10 月 25 日整理并首次发布,页面日期用于归档对应时期的实践;后续修整一并写入。产品开放范围以文中链接的公开说明为准。

有时一次软件发布已经完成大半:代码检查过,软件包也做好了,最后却在下载或读取文件时遇到一次网络失败。

如果处理方式只有“整套重新跑”,就要再次等前面已经成功的步骤。尤其是 Mac 软件还涉及签名和较大的安装文件,一次暂时的读取问题,会被放大成很长的等待。

整理陪练的交付准备时,我更想把失败放回它实际发生的位置:哪些结果已经可靠地留下,哪一步可以安全地再做一次?

01 / 已经可靠完成的部分留下来
已经可靠完成的部分留下来 箭头表示阶段接续;示意中的局部重试仍受次数和总期限约束。 构建与签名完成 保留可追溯的软件包 读取阶段暂时失败 只恢复允许重试的这一步 重新取得并校验 通过后再继续发布
箭头表示阶段接续;示意中的局部重试仍受次数和总期限约束。

重试之前,先分清这一步在做什么#

读取一份固定文件,和提交一次会改变状态的操作,风险不同。前者通常可以设计为重新读取;后者要先确认上一次究竟有没有生效。

即便是读取,也不能对所有错误统一重试。临时连接中断、上游暂时不可用,可能值得再试;来源不对、没有权限、内容校验失败,反复请求通常不会变好。

看到的情况我会先怎样处理
暂时网络中断看是否允许有限次数的读取重试
权限或来源被拒绝停下来核对,不把拒绝当作网络抖动
文件不完整丢弃本次半成品,再按规则重新取得
已触发安装等写操作查询原操作状态,避免重复执行

小步骤能重试,整个任务也要有截止点#

重试可以解决一次偶发失败,也可能让失败永远不结束。我会同时保留单次请求的超时、允许的重试次数和外层任务的总期限。

还有一个容易遗漏的地方:重试不能把整个截止时间重新归零。否则每一小步都看起来“还没超时”,用户却已经等了很久。

错误也要回到能行动的描述上。比如“读取阶段连接中断,可以稍后重试”和“内容校验未通过,未进入发布”,比统一写“未知错误”更有帮助。公开信息只给出阶段和类别,不显示内部主机或鉴权信息。

02 / 先判断错误,再决定是否重试
先判断错误,再决定是否重试 错误类别示意,不提供内部地址、读取凭据或生产操作参数。 暂时读取失败 连接中断 允许有界重试 明确拒绝或不符 权限与来源错误 停止并核对原因
错误类别示意,不提供内部地址、读取凭据或生产操作参数。

重新拿到文件以后,仍要重新核对#

下载完成只说明这次收到了内容,还要检查长度、摘要和来源。上一次残留的半包不能被当成完整新包,重试也不应跳过已有验证。

我希望文件只有在验证完成后,才进入下一环节;验证失败的临时内容单独处理,已经验证的原始结果仍然能找回。这样一个小步骤失败,不会顺便破坏前面完成的工作。

可以用固定的合成文件测试:第一次读取中断,第二次正常;连续失败直到总期限;权限拒绝时不继续;收到不匹配内容时不发布。每一种都应该留下不同结果。

这项改动,应该怎样看收益#

最直接的收益是减少不必要的全量重跑。要量化,还得记录失败发生在哪个阶段、局部恢复花多久,以及有多少次真的因此避免了重新打包。

一条恢复测试通过,说明这种失败路径有依据;它不代表生产网络永远稳定,也不代表尚未开放的在线更新已经正式启用。

我现在更愿意把发布流程设计成几个有明确结果的小步骤。成功的部分能留下,失败的部分能定位,重试才不需要把整件事推倒重来。