18-05 复现写入后的失败
题目
在业务提交之后制造失败,关闭并重新打开检查点后重试。核对最终计划只有一行,再试同一操作编号携带另一份内容,保留对应失败用例。
推导与做法
第一次保存已经提交 plans,但节点返回前抛错,因此检查点仍指向待完成的 save。重开 SQLite saver 后,从旧状态重试,operation_id 必须保持不变。
PlanStore 的唯一键让第二次执行读取原行,不再插入。题解分别检查中断后和重试后的行数都为 1,再用同一编号提交不同分钟数,得到 ValueError。只有“没有重复行”还不足以证明两个不同动作没有被错误合并。
过程图
%% 每个节点保留输入、执行位置或执行后的实际状态。
flowchart TD
A["save进入:检查点保留operation_id=op1"]
A --> B["业务INSERT提交,plans已有1行"]
B --> C["节点返回前故障,图仍待save"]
C --> D["关闭连接,再打开旧检查点"]
D --> E["重试save:仍使用op1和原内容"]
E --> F["唯一键命中已有行,读取原id"]
F --> G["图变为saved,plans仍为1行"]
E --> H["若同op1换成另一分钟数"]
H --> I["内容比较失败,拒绝覆盖原计划"]
classDef default fill:#EEF0FB,stroke:#4657B5,color:#24324A
linkStyle default stroke:#4657B5
实现与运行
查看带注释实现。本题与相关处理函数放在同一章节代码文件中;启动工具负责定位相邻项目和选择题号。
在配套目录的 LangChain与AgentRuntime/study_agent 中运行。先按项目 README 执行 uv sync --locked。本章先执行 uv sync --locked --all-extras。18-06 还需执行 uv pip install -e "../../FastAPI/api_project",接入前面 API 声明的依赖;之后使用 --no-sync 保留这份组合环境。
# 使用项目解释器运行本题,题号决定执行哪一组演示。
uv run --no-sync python "../../学习索引/参考实现/代码/ch18.py" 18-05
程序按题号输出处理后的值、查询结果或状态。先和前面的手算比较,再修改一项输入重跑。
查看本题运行结果
# 与上面的手算状态和题目数值逐项比较。
{
"rows_after_crash": 1,
"rows_after_retry": 1,
"status": "saved",
"changed_payload_rejected": true
}