从零实现持久化执行:先把工作流变成可验证的纯状态机
为什么不是再写一个任务队列普通任务队列擅长“把函数放到另一台机器执行”却很难回答更麻烦的问题进程在扣款之后、写订单之前崩溃重启后究竟应该从哪里继续如果把整个函数重新跑一遍扣款可能发生两次如果直接标记失败已经发生的副作用又无人处理。持久化执行的核心不是更快地调度函数而是让一次跨越数分钟、数天甚至数月的业务过程在任意中断后仍能从确定位置恢复。本系列贯穿项目叫miniflow。我们用一个“旅行预订”流程持续演进锁定预算、预订航班、预订酒店、最终确认。后续会故意加入崩溃、重复投递、并发抢占、长定时器、补偿以及代码升级。第一篇暂时不碰数据库和网络先解决最容易被低估的基础把“下一步做什么”从一串隐含在调用栈里的控制流变成显式、可测试的数据变换。许多工作流系统的第一个坑是一上来就写执行器。执行器里同时查状态、调接口、捕获异常、推进游标最终得到一个无法重放的巨大循环。更稳妥的边界是决策函数只读取历史状态和一个事件返回新状态以及待执行命令真正的网络调用由外层执行。这样决策层没有时间、随机数、网络和全局变量相同输入永远得到相同输出。这个性质叫确定性也是以后恢复的地基。建模事件、命令与不可变状态事件描述“已经发生什么”例如预算已锁定命令描述“希望外部做什么”例如请求预订航班。两者不能混用。如果决策函数自己调用航司 API重放历史时就会再次订票如果它只产生book_flight命令重放时便能识别这条命令过去已经完成。状态使用冻结的数据类迫使每次转移构造新值避免测试之间共享可变对象。把下面内容保存为miniflow.py。decide是本系列最重要的函数后九篇都会复用或扩展它。注意未知事件不是默默忽略而是立即失败。悄悄吞掉事件会让旧版本程序看似运行实际却在错误状态上继续推进这是事件驱动系统里很危险的“兼容性幻觉”。fromdataclassesimportdataclass,replacefromtypingimportNamedTupledataclass(frozenTrue)classTripState:trip_id:strphase:strnewbudget_token:str|NoneNoneflight_ref:str|NoneNonehotel_ref:str|NoneNoneclassEvent(NamedTuple):kind:strdata:dictclassCommand(NamedTuple):kind:strdata:dictdefdecide(state:TripState,event:Event)-tuple[TripState,list[Command]]:ifstate.phasenewandevent.kindtrip_requested:newreplace(state,phaselocking_budget)returnnew,[Command(lock_budget,{trip_id:state.trip_id})]ifstate.phaselocking_budgetandevent.kindbudget_locked:newreplace(state,phasebooking_flight,budget_tokenevent.data[token])returnnew,[Command(book_flight,{trip_id:state.trip_id})]ifstate.phasebooking_flightandevent.kindflight_booked:newreplace(state,phasebooking_hotel,flight_refevent.data[ref])returnnew,[Command(book_hotel,{trip_id:state.trip_id})]ifstate.phasebooking_hotelandevent.kindhotel_booked:newreplace(state,phaseconfirmed,hotel_refevent.data[ref])returnnew,[]raiseValueError(finvalid transition:{state.phase}{event.kind})运行输出模块定义成功无标准输出用一条历史证明状态转移下面的脚本不是“演示式伪代码”而是可以直接运行的最小测试驱动器。保存为demo_101.py与miniflow.py放在同一目录。它明确列出历史事件每次把上一步状态作为下一步输入并打印新阶段和命令。命令只被打印没有真正执行这恰好体现决策与副作用的分界。fromminiflowimportTripState,Event,decide history[Event(trip_requested,{city:成都}),Event(budget_locked,{token:B-7}),Event(flight_booked,{ref:F-8}),Event(hotel_booked,{ref:H-9}),]stateTripState(trip-001)emitted[]forposition,eventinenumerate(history,start1):state,commandsdecide(state,event)emitted.extend(command.kindforcommandincommands)print(position,event.kind,,state.phase,[command.kindforcommandincommands])assertstate.phaseconfirmedassertstate.flight_refF-8assertstate.hotel_refH-9assertemitted[lock_budget,book_flight,book_hotel]print(final:,state)运行输出1 trip_requested locking_budget [lock_budget] 2 budget_locked booking_flight [book_flight] 3 flight_booked booking_hotel [book_hotel] 4 hotel_booked confirmed [] final: TripState(trip_idtrip-001, phaseconfirmed, budget_tokenB-7, flight_refF-8, hotel_refH-9)为什么纯函数边界值得坚持第一它让失败语义清楚。事件进入之前世界没有变化事件成功应用之后新状态和命令一起产生。虽然 Python 返回两个值不是数据库事务但这个结构为下一篇把两者原子写入 SQLite 留出了位置。第二它让测试组合简单。无需启动 worker、伪造 HTTP 或等待定时器只要枚举事件序列即可覆盖业务分支。第三它让历史具备解释力。看到flight_booked就知道航班副作用曾成功而不是从某个布尔字段猜测。一个非平凡踩坑是“把当前阶段当成唯一事实”。阶段只是历史的折叠结果不能替代历史。假设状态显示booking_hotel我们仍不知道航班命令是否发送过两次、哪次成功、响应是什么。当前篇用阶段保障合法转移下一篇则保存每个事实。另一个坑是事件负载随意使用字典。字典方便起步却会把拼写错误推迟到运行期工程中应给事件做版本化校验。我们会在第八篇专门处理模式升级现在先保持依赖为零让决定性边界一眼可见。还要记住确定性不等于“永远按同一业务结果运行”。航司价格当然会变化但变化应作为一次外部活动的结果写入事件然后成为确定历史的一部分。决策函数不能在重放时重新查询价格、读取当前日期或生成随机 ID。若确实需要这些值就发出命令让执行器获取后以事件返回。这条规则看似拘谨实际是持久化执行能够跨崩溃延续的根本。本篇产出与下一步现在我们有了miniflow.py中的TripState、Event、Command和decide以及一条可重复验证的旅行历史。它仍然只活在内存里进程退出就消失。下一篇会原样复用这些类型和函数把输入事件与产生的命令在一个 SQLite 事务里追加到日志得到第一个真正可恢复的持久化核心。 觉得有用就点个赞 收藏方便回头查阅有疑问直接在评论区留言我看到都会回。 文章里的代码都能直接跑。想要可直接 clone 的完整工程 配套部署脚本 / 踩坑清单评论一声或发邮件到cj2664qq.com我免费发你。如果你正好在做类似系统、或有工程化难题想找人做也欢迎邮件聊一句——我按实际情况评估能落地的就接单或出方案。评论和邮件都能直接找到我不用跳别的平台。

相关新闻

MySQL日期格式化函数DATE_FORMAT()详解与应用实践

MySQL日期格式化函数DATE_FORMAT()详解与应用实践

1. MySQL日期格式化基础与常见场景MySQL中的日期时间处理是数据库操作中最频繁的需求之一。DATE_FORMAT()函数作为核心的日期格式化工具,其基本语法为:DATE_FORMAT(date, format)其中date参数可以是DATE、DATETIME或TIMESTAMP类型的列或值,fo…

2026/8/3 11:53:19 阅读更多 →
测试用例管理平台架构设计与实践指南

测试用例管理平台架构设计与实践指南

1. 测试用例管理平台的核心价值与定位 在软件研发的生命周期中,测试环节的质量直接决定了最终产品的稳定性。传统测试管理往往面临三个典型痛点:用例散落在Excel/邮件中难以追溯、多人协作版本混乱、执行结果与需求脱节。这正是测试用例管理平台要解决的…

2026/8/3 11:53:18 阅读更多 →
SSM+Vue构建教育资源共享平台实战

SSM+Vue构建教育资源共享平台实战

1. 项目背景与核心价值去年接手某教育机构的课程体系升级项目时,我第一次系统接触到"小码创客"这个教学品牌。作为面向8-16岁青少年的编程教育平台,其最大的痛点在于教学资源分散——课件、案例、项目模板分散在多个老师的电脑里,新…

2026/8/3 11:53:18 阅读更多 →

最新新闻

089、Zephyr RTOS驱动开发实战:定时器驱动

089、Zephyr RTOS驱动开发实战:定时器驱动

Zephyr RTOS驱动开发实战:定时器驱动 从一次产线死锁说起 去年秋天帮客户调试一套工业分拣系统,Zephyr跑在STM32H743上,四个定时器分别驱动步进电机、采集编码器、触发相机和看门狗喂狗。产线跑了三天,突然在凌晨三点死锁——电机停转,相机不触发,看门狗也没复位。远程…

2026/8/3 12:23:40 阅读更多 →
【多进程Topic通信系统设计文档】

【多进程Topic通信系统设计文档】

多进程Topic通信系统设计文档1. 系统概述1.1 项目背景1.2 系统目标2. 架构设计2.1 整体架构架构图概览核心组件说明1. 客户端层(Client Layer)2. Topic Broker(TCP通信层)3. 队列层(Queue Layer)4. 处理层&…

2026/8/3 12:23:40 阅读更多 →
Audiveris终极指南:5步快速上手免费开源乐谱识别软件

Audiveris终极指南:5步快速上手免费开源乐谱识别软件

Audiveris终极指南:5步快速上手免费开源乐谱识别软件 【免费下载链接】audiveris Latest generation of Audiveris OMR engine 项目地址: https://gitcode.com/gh_mirrors/au/audiveris Audiveris是一款功能强大的开源光学音乐识别(OMR&#xff0…

2026/8/3 12:23:40 阅读更多 →
3分钟上手Faster-Whisper-GUI:免费开源的语音转文字终极方案

3分钟上手Faster-Whisper-GUI:免费开源的语音转文字终极方案

3分钟上手Faster-Whisper-GUI:免费开源的语音转文字终极方案 【免费下载链接】faster-whisper-GUI faster_whisper GUI with PySide6 项目地址: https://gitcode.com/gh_mirrors/fa/faster-whisper-GUI 你是一个文章写手,你负责为开源项目写专业易…

2026/8/3 12:23:40 阅读更多 →
告别网盘下载龟速:九大主流平台直链解析工具全攻略

告别网盘下载龟速:九大主流平台直链解析工具全攻略

告别网盘下载龟速:九大主流平台直链解析工具全攻略 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘…

2026/8/3 12:23:40 阅读更多 →
如何优化HMCL启动器兼容性:深入解析跨平台Minecraft启动器的技术架构与性能调优

如何优化HMCL启动器兼容性:深入解析跨平台Minecraft启动器的技术架构与性能调优

如何优化HMCL启动器兼容性:深入解析跨平台Minecraft启动器的技术架构与性能调优 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(He…

2026/8/3 12:22:39 阅读更多 →

日新闻

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

PC服务器具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构一、前言:具身智能需要“混合算力闭环系统”传统人工智能依赖云端静态数据集训练,不具备物理交互能力,无法适应真实世界的不确定性。具身智能(Embodied…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

前言构建机器人、具身智能这类分布式实时系统,通信底座直接决定整套系统的实时性、容错性、组网能力。分布式领域长期存在 4 类经典通信架构:点对点模式、Broker 中间代理模式、广播模式、以数据为中心(DDS)模式。很多开发者疑惑&…

2026/8/3 0:00:47 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/3 4:58:13 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/3 1:53:31 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/3 4:36:35 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/3 5:19:38 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/3 8:27:36 阅读更多 →