Agent 改了文件又调用远端接口,WAL 能一起回滚吗?

发布时间:2026/10/25 21:00:10
Agent 改了文件又调用远端接口,WAL 能一起回滚吗?

假设Agent先更新本地任务状态,再向远端提交一次素材处理,最后回复丢了。本地事务回滚以后,远端任务会跟着消失吗?这个问题不能靠把日志叫作WAL来回答。

SQLite的WAL说明描述的是数据库文件的提交与检查点机制。它并不把HTTP服务或普通文件写入纳入同一个事务。该页面是持续维护的技术文档,本轮访问日为2026-10-23,不能把访问日写成WAL的发布日期。

先分开三种状态

本地数据库能证明什么,取决于事务和持久化设置;工作区文件需要自己的原子替换及恢复协议;远端服务则需要请求标识、幂等性约定或查询接口。把三者都写进一个Rust结构体,不会得到跨系统原子性。

最危险的不是明确失败,而是超时:请求可能没到,也可能已完成只是回包丢了。这时立即再发一遍,可能重复扣费或重复产生任务。撤销操作如果存在,通常也是新的业务动作,并不等于数据库rollback。

一个完全离线的反例

为了让事务边界看得见,这里直接使用Python标准库里的SQLite。远端用内存集合代替,绝不连接外部服务。反例只需要检查:数据库回滚能否顺便删除集合元素。

import sqlite3 import tempfile from pathlib import Path with tempfile.TemporaryDirectory(prefix="local-wal-check-") as tmp: db = sqlite3.connect(str(Path(tmp) / "state.db")) assert db.execute("PRAGMA journal_mode=WAL").fetchone()[0] == "wal" db.execute("CREATE TABLE intent(id TEXT PRIMARY KEY, state TEXT)") db.commit() remote_mock = set() db.execute("BEGIN") db.execute("INSERT INTO intent VALUES (?,?)", ("req-1", "pending")) remote_mock.add("req-1") # only an in-memory stand-in for a remote effect db.rollback() assert db.execute("SELECT count(*) FROM intent").fetchone()[0] == 0 assert "req-1" in remote_mock print("local rollback passed; mock remote effect remains") print("SQLite", sqlite3.sqlite_version) db.close()

Python 3.9.6执行通过,结果是本地记录消失,模拟的远端效果仍在。代码还打印实际SQLite版本,避免把Python版本当数据库版本。本轮结果记录在验证台账中。

这个实验没有模拟网络故障分布,也没有证明磁盘断电恢复,只证明两个不同状态容器之间不存在自动回滚关系。搬回Rust使用rusqlite或其他驱动时,这个边界不变,但连接、事务和错误类型还要重新测试。

我会怎样记录一次副作用

先在本地提交intent,给操作一个稳定的id,再执行远端调用;得到明确确认后记录结果。回复未知时状态叫unknown,保留原id和时间,不直接标failed。恢复程序优先查询同一id;只有服务端明确支持幂等重试,才按其约定重试。

outbox能保证“待发送意图与本地业务状态同事务提交”,不保证接收方只执行一次。接收方还要去重,去重窗口和结果保留时间也要明确。图里的retry safely有这个前提,不能仅凭日志存在就点击重试。

这篇的结论很窄:WAL可以支撑本地恢复设计,但不能替远端签原子性保证。学习Agent工具链时,把unknown保留下来,比在回滚函数里打印“全部恢复”更有用。