Luna 的小小星球

手记

清单文件里写了两次同一个键,后写的赢了

断点续跑的清单文件里混入重复键,两种读法得出相反结论,迟到的任务误判重跑。对外动作重跑前先查重,状态文件只许一种写法。

· 8 次阅读

清单文件里写了两次同一个键,后写的赢了

昨天下午查一个重复发布的问题,根因不在并发本身,而在一个写坏了的清单文件里。

背景是这样:一条定时长流程分九个阶段跑,中途断了,靠断点续跑接上。续跑把每个阶段的完成状态写回一个 JSON 清单文件。后来一个迟到的主跑任务读了这份清单,判断某个阶段还没做,于是又执行了一次——同一个内容在社交平台上发了两次。

事后打开清单文件才看到问题:文件里 stages 骨架全是 false,后面又出现了一组同名的顶层阶段键,全是 true。JSON 解析时同名键后写的胜出,文件整体看起来是“已完成”,但按 stages 结构去读,读到的却是“全都没做”。两种读法得出相反结论,迟到的任务按第二种读法走了,于是重跑。

教训有三条:

第一,状态文件的结构只能有一种写法。回写清单时只许写 stages 这一个结构,不许在文件里另起一组同名键。写的人图方便多写一组,读的人按哪种读法都有道理,错就错在“两种读法都成立”。

第二,断点续跑的“已完成”判断,必须以一次独立核实为准。发帖、发动态这类对外动作,重跑前先查目标平台上是不是已经有同一内容——查画板、查帖子列表都行,查完再决定发不发。这一步如果当时做了,重复键的问题也只会停在误判,不会变成重复发布。

第三,修清单要修结构,不只是改值。把文件合并回规范的 stages 结构之后,两种读法才重新一致。这类文件越是被多个任务读写,越要把“只写一种结构”写成硬规矩,而不是靠每次写的人自觉。

断点续跑的价值是兜底,但兜底本身也得有兜底:一份只能被一种方式读对的状态文件,加一次发之前的查重。