编码母题 / P1 / Agent 运行时 / 03
支持检查点的可恢复状态机
先读清题意与边界,独立尝试,再展开思路并对照可运行的参考代码。
重要程度高价值难度困难预计完成45–60 分钟
题目是什么
实现可恢复的显式状态机。合法转移后保存检查点并递增版本;恢复不能让旧实例覆盖新版本,也不能让调用者修改存储内部对象。
输入输出示例
两个实例从同一版本恢复,先提交者成功,后提交者得到版本冲突。
练习起手式与验证
复制代码后补全空方法,再运行下方三组验证;复杂题所需的辅助类型与输入准备一并放在代码块中。
/*
* 题目:支持检查点的可恢复状态机
* 要求:实现可恢复的显式状态机。合法转移后保存检查点并递增版本;恢复不能让旧实例覆盖新版本,
* 也不能让调用者修改存储内部对象。
* 示例:两个实例从同一版本恢复,先提交者成功,后提交者得到版本冲突。
*/
const transitions = {
pending: ["running", "cancelled"],
running: ["waiting_approval", "completed", "failed", "cancelled"],
waiting_approval: ["running", "failed", "cancelled"],
completed: [],
failed: [],
cancelled: [],
};
const clone = (value) => structuredClone(value);
class MemoryCheckpointStore {
constructor() {}
save(checkpoint, expectedVersion) {}
load(runId) {}
}
class RunStateMachine {
constructor(store, checkpoint) {}
static create(store, runId, data = {}) {}
static restore(store, runId) {}
transition(nextStatus, patch = {}) {}
snapshot() {}
}
const store = new MemoryCheckpointStore();
const machine = RunStateMachine.create(store, "r1", { step: 0 });
machine.transition("running", { step: 1 });
machine.transition("waiting_approval");
const restored = RunStateMachine.restore(store, "r1");
console.log(restored.snapshot().status); // 预期:"waiting_approval"
restored.transition("running");
restored.transition("completed");
console.log((() => { try { (() => restored.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
console.log((() => { try { (() => machine.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
/*
* 题目:支持检查点的可恢复状态机
* 要求:实现可恢复的显式状态机。合法转移后保存检查点并递增版本;恢复不能让旧实例覆盖新版本,
* 也不能让调用者修改存储内部对象。
* 示例:两个实例从同一版本恢复,先提交者成功,后提交者得到版本冲突。
*/
const transitions = {
pending: ["running", "cancelled"],
running: ["waiting_approval", "completed", "failed", "cancelled"],
waiting_approval: ["running", "failed", "cancelled"],
completed: [],
failed: [],
cancelled: [],
};
const clone = (value) => structuredClone(value);
class MemoryCheckpointStore {
constructor() {}
save(checkpoint, expectedVersion) {}
load(runId) {}
}
class RunStateMachine {
constructor(store, checkpoint) {}
static create(store, runId, data = {}) {}
static restore(store, runId) {}
transition(nextStatus, patch = {}) {}
snapshot() {}
}
const store = new MemoryCheckpointStore();
const machine = RunStateMachine.create(store, "r1", { step: 0 });
machine.transition("running", { step: 1 });
machine.transition("waiting_approval");
const restored = RunStateMachine.restore(store, "r1");
console.log(restored.snapshot().status); // 预期:"waiting_approval"
restored.transition("running");
restored.transition("completed");
console.log((() => { try { (() => restored.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
console.log((() => { try { (() => machine.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)解题思路
展开思路、不变量与常见边界
关键切入点:用状态转移表定义合法边,保存时 compare-and-set 校验期望版本。
核心模型:状态与副作用分离;Checkpoint 是可恢复事实,不是日志文本。不变量: version 单调递增;同一 runId 的版本不能倒退;恢复结果是深拷贝,调用方不能修改 仓库内部数据。生产系统还需事务性 Outbox、Step 幂等和 Schema 版本迁移。
参考代码与验证
“关键机制”注释用于解释实现,下载链接提供未经页面注释修改的原始 JS 文件。
const transitions = {
pending: ["running", "cancelled"],
running: ["waiting_approval", "completed", "failed", "cancelled"],
waiting_approval: ["running", "failed", "cancelled"],
completed: [],
failed: [],
cancelled: [],
};
const clone = (value) => structuredClone(value);
// 关键机制:用状态转移表定义合法边,保存时 compare-and-set 校验期望版本。
class MemoryCheckpointStore {
constructor() {
this.data = new Map();
}
save(checkpoint, expectedVersion) {
const current = this.data.get(checkpoint.runId);
const actual = current?.version ?? 0;
if (actual !== expectedVersion)
throw new Error("checkpoint version conflict");
this.data.set(checkpoint.runId, clone(checkpoint));
}
load(runId) {
const value = this.data.get(runId);
return value ? clone(value) : null;
}
}
class RunStateMachine {
constructor(store, checkpoint) {
this.store = store;
this.state = checkpoint;
}
static create(store, runId, data = {}) {
return new RunStateMachine(store, {
runId,
status: "pending",
version: 0,
data: clone(data),
});
}
static restore(store, runId) {
const value = store.load(runId);
if (!value) throw new Error("checkpoint not found");
return new RunStateMachine(store, value);
}
transition(nextStatus, patch = {}) {
if (!transitions[this.state.status].includes(nextStatus))
throw new Error(
`invalid transition: ${this.state.status} -> ${nextStatus}`,
);
const previousVersion = this.state.version;
const next = {
...this.state,
status: nextStatus,
version: previousVersion + 1,
data: { ...this.state.data, ...clone(patch) },
};
this.store.save(next, previousVersion);
this.state = next;
return this.snapshot();
}
snapshot() {
return clone(this.state);
}
}
// 三组以上可直接运行的验证。
const store = new MemoryCheckpointStore();
const machine = RunStateMachine.create(store, "r1", { step: 0 });
machine.transition("running", { step: 1 });
machine.transition("waiting_approval");
const restored = RunStateMachine.restore(store, "r1");
console.log(restored.snapshot().status); // 预期:"waiting_approval"
restored.transition("running");
restored.transition("completed");
console.log((() => { try { (() => restored.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
console.log((() => { try { (() => machine.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
const transitions = {
pending: ["running", "cancelled"],
running: ["waiting_approval", "completed", "failed", "cancelled"],
waiting_approval: ["running", "failed", "cancelled"],
completed: [],
failed: [],
cancelled: [],
};
const clone = (value) => structuredClone(value);
// 关键机制:用状态转移表定义合法边,保存时 compare-and-set 校验期望版本。
class MemoryCheckpointStore {
constructor() {
this.data = new Map();
}
save(checkpoint, expectedVersion) {
const current = this.data.get(checkpoint.runId);
const actual = current?.version ?? 0;
if (actual !== expectedVersion)
throw new Error("checkpoint version conflict");
this.data.set(checkpoint.runId, clone(checkpoint));
}
load(runId) {
const value = this.data.get(runId);
return value ? clone(value) : null;
}
}
class RunStateMachine {
constructor(store, checkpoint) {
this.store = store;
this.state = checkpoint;
}
static create(store, runId, data = {}) {
return new RunStateMachine(store, {
runId,
status: "pending",
version: 0,
data: clone(data),
});
}
static restore(store, runId) {
const value = store.load(runId);
if (!value) throw new Error("checkpoint not found");
return new RunStateMachine(store, value);
}
transition(nextStatus, patch = {}) {
if (!transitions[this.state.status].includes(nextStatus))
throw new Error(
`invalid transition: ${this.state.status} -> ${nextStatus}`,
);
const previousVersion = this.state.version;
const next = {
...this.state,
status: nextStatus,
version: previousVersion + 1,
data: { ...this.state.data, ...clone(patch) },
};
this.store.save(next, previousVersion);
this.state = next;
return this.snapshot();
}
snapshot() {
return clone(this.state);
}
}
// 三组以上可直接运行的验证。
const store = new MemoryCheckpointStore();
const machine = RunStateMachine.create(store, "r1", { step: 0 });
machine.transition("running", { step: 1 });
machine.transition("waiting_approval");
const restored = RunStateMachine.restore(store, "r1");
console.log(restored.snapshot().status); // 预期:"waiting_approval"
restored.transition("running");
restored.transition("completed");
console.log((() => { try { (() => restored.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
console.log((() => { try { (() => machine.transition("running"))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
复杂度分析
时间复杂度:O(D)/转移。每次保存与返回快照都要克隆大小为 D 的状态数据。
空间复杂度:O(D)/检查点。仓库保存状态副本,递归或额外队列并不存在。