首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >#WorkBuddy# 脚本崩了别急着重跑:给批量提交加"已提交状态机"

#WorkBuddy# 脚本崩了别急着重跑:给批量提交加"已提交状态机"

原创
作者头像
用户12814938
修改于 2026-10-14 14:04:46
修改于 2026-10-14 14:04:46
630
举报

我平时用 AI 助手加自动化脚本管理一批电商店铺,最重的一类操作是批量提交:批量复制商品上架、批量改配置。这类操作有个共同点——每一步都是"提交"动作,提交成功就是既成事实。前几天我踩了一个几乎所有写脚本的人都躲不开的坑:脚本崩了,重跑,结果提交了两遍。

场景:一次例行批量复制

那天晚上跑一个批量复制上架的脚本,逻辑很朴素:遍历几十个店铺,每个店铺做"选源商品→填参数→点提交→记一条日志"。脚本跑到一半进程崩了。第一反应很自然:重新跑一遍呗,反正断在哪补哪。

重跑之后过了一会儿我去后台核对,才发现不对劲——有若干商品出现了双份。也就是说,崩溃发生在"已经在服务端提交成功"之后、"本地写日志"之前。脚本重跑时看本地记录:没有这条,认为没做过,于是老老实实又提交了一遍。服务端可不管你本地怎么想的,来了就收。

坑:本地记录和服务端状态之间存在窗口

复盘下来,真正的坑不是崩溃本身,而是脚本隐含了一个错误假设:本地没记录 = 业务没发生。实际上任何一个"提交+落盘"的两步操作,两步之间都有窗口。崩溃、断网、超时、进程被杀,都可能正好落在这个窗口里,而且你事后无法从本地判断它到底落没落进去。

更麻烦的是"状态不明"比"明确失败"更危险。明确失败你可以放心重试;状态不明时重试,就是在赌服务端没收到。批量场景下赌错一次,就要去后台一条条找重复记录、手工清理重复链接,清理成本远高于多等五分钟。

解法一:重跑前先核实,宁停勿试

现在我的规矩改成了:疑似已提交(包括崩溃中断、超时、页面白屏)一律先核实,不核实不重跑。核实办法很简单——去后台的"复制记录"或商品管理列表里查目标记录存不存在。查到了,就当它成功,从断点之后继续;查不到,才允许重跑这一条。状态不明的时候宁可停下来等人判断,也不赌。

这个原则说出来平平无奇,但难在执行:重跑是零成本动作,人会本能地选择它。所以要把它变成硬规矩写进流程,而不是靠"下次注意"。

解法二:把提交做成状态机

第二层保险是从脚本结构上根治。我给脚本加了"提交状态机":把每个单元的执行过程拆成状态,每前进一步就落盘一次,而不是做完了才记一笔。核心状态流转长这样:

代码语言:txt
复制
pending -> selected -> filled -> submitting -> submitted
                |                          |
                +--> failed(可重试)         +--> unknown(需人工核实)

关键设计有三点。第一,submitting 和 submitted 是两个状态:请求发出去了就进 submitting,拿到服务端确认响应才写 submitted。第二,重启脚本时扫一遍状态表,submitted 直接跳过,submitting 和 unknown 一律拦下来走人工核实,只有 pending/failed 允许自动重试。第三,每条记录带一个幂等键(用商品唯一标识拼出来),重复跑也先查键再动手。

这样脚本崩在任何位置,重跑都是安全的:要么没提交(状态还在前段,正常续跑),要么已提交(状态表挡住),要么状态不明(主动停下来,而不是替服务端做决定)。

解法三:批量的容错要"停在点上"

还有个连带教训:批量脚本崩了之后,不要从店铺列表的开头整批重来,而是从状态表里第一个非终态的单元继续。整批重来等于把上面所有窗口全部重新打开一遍,前面成功的部分全暴露在双份风险里。

总结

这次事故没有造成大损失,但它暴露的问题是通用的:所有"写日志在提交之后"的脚本,都天然携带双份提交风险。三件事记下来:一是异常后默认不重提,先去服务端核实;二是提交动作做成状态机,逐步落盘、幂等键防重;三是重跑从断点续,不整批重来。宁可多花五分钟查记录,不要花一小时清重复——这句话现在贴在我的流程清单第一行。

附:关键过程实录

为了把这套状态机讲透,我把 demo 完整跑了一遍:第一次运行,脚本崩在提交窗口内,unit-3 停在 submitting;接着 --resume 续跑,已提交的两个单元被幂等跳过,窗口期单元被主动拦下、升级为 unknown 等人工核实;人工核实放行后再跑,五个单元全部到达终态 submitted,全程零双份。下面六张图依次是:首跑崩溃现场、每步落盘的状态表内容、续跑时"宁停勿试"的拦截现场、人工核实放行后的完整收尾、发布管线当天产生这篇文章的真实日志(可以看到"提交成功"和"结果落盘"之间就是那个窗口期)、以及社区创作中心后台里这篇文章的实时数据。

拿走就能用

代码语言:txt
复制
python state_machine_demo.py                            # 首跑:崩在提交窗口期,退出码 137
python state_machine_demo.py --resume                   # 续跑:submitted 跳过,unknown 停下等人工
python state_machine_demo.py --resume --confirm unit-3  # 人工核实后放行,跑完全程零双份

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 场景:一次例行批量复制
  • 坑:本地记录和服务端状态之间存在窗口
  • 解法一:重跑前先核实,宁停勿试
  • 解法二:把提交做成状态机
  • 解法三:批量的容错要"停在点上"
  • 总结
  • 附:关键过程实录
  • 拿走就能用
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档