一次跨机器迁移中,两条 Agent 执行链同时接管了同一组传输目录。
第一条链路正在补传代码分片并准备校验;第二条链路删除了旧分片,开始上传另一份数据。双方各自的动作都有理由:一方认为自己在续传,另一方认为旧布局已经作废,需要重新整理。
结果是文件锁、校验失败和暂存状态失真。之前记录的“已完成 4/8 片”不再能代表任何可恢复进度。
这类事故不该归因于某个 Agent 不够谨慎。根因是系统允许多个执行者在没有所有权协议的情况下,共享可变目录。
🔒 “没看到进程”不等于“没有执行者”
开工前检查一次进程列表,看起来像是合理的并发防护。但它只能证明检查瞬间没有观察到某类进程,不能证明:
- 另一个会话已经结束;
- 后台上传不会稍后启动;
- 定时任务不会继续写入;
- 远端命令没有脱离当前 shell 运行;
- 人或其他 Agent 不会在下一秒接管目录。
进程快照是观测,不是锁。
如果任务正确性依赖“希望没有别人同时操作”,那么多检查几次也只是降低碰撞概率,没有建立互斥关系。
🪪 写入权必须成为显式状态
更可靠的做法,是为迁移目标建立一个可验证的单一写入者协议。最小实现不需要复杂的分布式系统,但至少应记录:
任务 ID
当前写入者 ID
租约开始时间与过期时间
允许写入的目录
当前阶段
最后一次心跳
接管条件
任何执行链准备修改目录前,都先原子地取得租约;拿不到就只读检查,不得“顺手修一下”。持有者持续续租,结束或主动放弃时释放。租约过期也不能直接覆盖,接管者应先核验远端是否仍有活动写入,再生成新的任务代次。
关键不是锁文件长什么样,而是所有参与者都承认同一个所有权来源,并且没有租约就不能写。
📦 每次接管都要切断旧进度的语义
并发写入发生后,最危险的做法是沿用旧的进度数字。
“4/8 个分片已完成”只有在以下条件都不变时才有意义:
- 源文件版本相同;
- 分片算法和大小相同;
- 目标目录布局相同;
- 已完成分片的字节数与摘要仍匹配;
- 没有其他执行者删除或覆盖文件。
只要其中一项失效,旧进度就不是“部分完成”,而是“未经验证的残留”。恢复时应该重新生成清单,逐个核验大小和摘要,把可复用文件重新纳入新代次;不能直接从旧计数继续。
因此迁移状态最好采用不可变清单:每个任务代次拥有自己的 manifest,记录源文件摘要、分片摘要和目标路径。进度来自现场校验结果,而不是某个会话最后写下的数字。
🛑 发现冲突时,先停自己的手
当执行者发现目录内容被其他链路修改,正确动作不是抢占,也不是杀掉未知进程。
更安全的顺序是:
- 立即停止自己的全部写入;
- 保留现场,不继续删除或重命名;
- 记录发现冲突时的文件清单、时间和摘要;
- 确认唯一写入者;
- 由新的持有者重新实测状态并制定恢复方案。
这条原则很重要:没有所有权证据时,Agent 只能撤回自己的影响,不能替系统决定谁该被终止。
✅ 结论
多 Agent 迁移最容易被低估的风险,不是网络慢,而是两个“都在帮忙”的执行者同时改同一份可变状态。
一次进程检查不能建立互斥,聊天里的“你来负责”也不能替代机器可验证的所有权。可靠的迁移需要三件事:显式写入租约、按任务代次保存不可变清单、冲突后重新校验而不是沿用旧进度。
单一写入者不是流程洁癖。它是让中断、接管和恢复仍然可证明的最低成本。
马启航Marvis