ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

发布冻结期能做什么:把状态转换写成可重放的纯函数

发布冻结期能做什么:把状态转换写成可重放的纯函数

冻结期不适合临时替换基础设施,却适合把一个已有流程的状态规则写清楚。用固定事件重放一次,检查输入有没有被偷偷改掉,比补一段“系统已经稳定”的总结更有用。

先选一个很小的状态机

教学对象是声音素材的评审流程:DRAFT 提交后进入 REVIEW,审核通过变成 READY,人工撤回回到 DRAFT。音频上传、网络请求、通知和当前时间都放在外部。纯函数只回答:给定旧状态和事件,新状态是什么。

10 月 6 日的 Ironclad 官方案例讨论了计算机使用评估,但厂商报告和模拟任务不能当成本项目的生产证据;本轮重开确认发布日期与研究范围,不移植其效果数字。本篇采用独立构造样例,验证范围限于状态迁移。

为了重放,事件携带显式时间和版本,不能在 reducer 内调用 Date.now 或 Math.random。事件 ID 用于去重,version 用于拒绝过期写入。示例只保存小规模已见事件集合;真实持久日志还需分段快照与保留策略。

const start=Object.freeze({stage:'DRAFT',version:0,seen:Object.freeze([]),updatedAt:0}); function reduceAsset(state,event){ if(!event||typeof event.id!=='string'||!event.id||!Number.isSafeInteger(event.at)||event.at<0) throw Error('event'); if(state.seen.includes(event.id))return state; if(event.expectedVersion!==state.version)throw Error('version conflict'); if(event.at<state.updatedAt)throw Error('time order'); const transitions={DRAFT:{submit:'REVIEW'},REVIEW:{approve:'READY',withdraw:'DRAFT'},READY:{withdraw:'DRAFT'}}; const stage=transitions[state.stage]?.[event.type]; if(!stage)throw Error('invalid transition'); return {stage,version:state.version+1,seen:[...state.seen,event.id],updatedAt:event.at}; } function replay(events,initial=start){return events.reduce(reduceAsset,initial);} const demoEvents=[ {id:'e1',type:'submit',at:100,expectedVersion:0}, {id:'e2',type:'approve',at:200,expectedVersion:1} ];

重放要比较状态,也要看失败位置

图中 DONE 表示评审完成,对应代码的 READY,尚不代表已经发布。PURE CORE 指确定性转换,EFFECTS OUTSIDE 指网络等外部行为;它不是部署流水线截图。对同一初始状态和事件序列,纯函数应产生相同结果。未知迁移直接报错,让调用者处理,而不是悄悄跳过后继续写入。

测试时冻结初始状态和嵌套数组,可以发现直接 push 或原地修改。对复杂对象需要递归冻结;浅冻结不保护所有子对象。还要检查重复投递不重复增版本、乱序时间不会悄悄覆盖、过期 version 能被发现。

纯函数守不了数据库事务

两个请求都读到 version=3,各自计算 version=4,纯函数都可能合法。存储层必须使用条件更新或事务保证只有一个提交成功。通知也不能在 reducer 里直接发送,否则重放会重复通知;可把副作用写入事务 outbox,再由独立消费者幂等执行。

本例没有数据库和消息系统,因此不宣称并发安全或恰好一次通知。通过的只是确定性、不可变输入、非法迁移、重复 ID 和版本冲突。冻结期能交付的是一份清楚的规则和可重跑样例,是否发布仍由既有发布流程决定。

复现记录

本轮在 Node.js v26.3.0 中运行随文核心逻辑的构造样例,进程退出码为 0。测试输出:

PASS: replay determinism, immutable input, duplicate event, invalid transition, version conflict, time order

将上方完整代码保存为 example.mjs,以 Node.js 26 执行 node example.mjs 可加载核心与教学输入;函数默认不访问网络、模型或硬件。浏览器适配入口需要明确传入对应对象,本轮未执行这些入口。上面的通过项来自独立构造样例,不能替代集成测试。

资料与时效

  • Advancing computer use with Ironclad:2026-10-06。
  • HTML Living Standard: Server-sent events:首次发布日期未核实;更新 2026-10-22。

本稿对应原预排时段;实际发布前须人工复核来源更正、SDK/API 版本及可用性,不据此预言 10 月 24–31 日的新事件。

返回列表