用 SQLite 事件日志给工作流装上“黑匣子”
从上一篇的纯状态机继续上一篇产出的miniflow.py定义了TripState、Event、Command与纯函数decide。本篇把它们当作既定输入不重写业务规则demo_102.py会导入Event和decide而数据库只负责可靠记录。上一篇的输出是内存中的事件序列和最终TripState本篇要把同样的序列变成可查询、可重放、可审计的持久化日志。为什么选 SQLite 而不是先上 Kafka持久化执行最关键的第一步不是吞吐量而是事务边界。单机 SQLite 提供真正的提交、唯一约束、崩溃恢复和清楚的文件形态足以把协议验证正确。事件日志采用只追加模型不更新旧事件不把最终状态覆盖到一行 JSON。追加日志保留因果过程后面才能重放、迁移和解释故障。等模型稳定后再把相同协议迁到 PostgreSQL 或分区日志远比一开始在分布式组件里调试语义容易。设计日志表和原子追加我们为每个工作流维护单调递增的seq。主键(workflow_id, seq)同时承担顺序约束和并发冲突检测。kind是事件类型payload使用稳定排序的 JSONcreated_at仅用于运维观察绝不能参与业务决策。WAL 模式允许读者不阻塞写者synchronousFULL更偏安全代价是每次提交可能触发刷盘。保存为event_store.py。这里有一个容易漏掉的细节连接级 PRAGMA 必须在每个新连接上设置不能以为初始化数据库时设置一次就永久有效。journal_modeWAL会持久化但foreign_keys、busy_timeout等很多选项不会。当前代码每次打开连接都走connect把行为集中起来。importjsonimportsqlite3fromcontextlibimportcontextmanagerfrompathlibimportPath SCHEMA CREATE TABLE IF NOT EXISTS events ( workflow_id TEXT NOT NULL, seq INTEGER NOT NULL, kind TEXT NOT NULL, payload TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (workflow_id, seq) ); classEventStore:def__init__(self,path:str):self.pathPath(path)withself.connect()asdb:db.executescript(SCHEMA)contextmanagerdefconnect(self):dbsqlite3.connect(self.path,timeout5)db.row_factorysqlite3.Row db.execute(PRAGMA journal_modeWAL)db.execute(PRAGMA synchronousFULL)try:yielddb db.commit()exceptException:db.rollback()raisefinally:db.close()defappend(self,workflow_id:str,expected_seq:int,kind:str,payload:dict)-int:next_seqexpected_seq1bodyjson.dumps(payload,ensure_asciiFalse,sort_keysTrue)withself.connect()asdb:db.execute(INSERT INTO events(workflow_id, seq, kind, payload) VALUES (?, ?, ?, ?),(workflow_id,next_seq,kind,body),)returnnext_seqdefload(self,workflow_id:str)-list[dict]:withself.connect()asdb:rowsdb.execute(SELECT seq, kind, payload FROM events WHERE workflow_id? ORDER BY seq,(workflow_id,)).fetchall()return[{seq:row[seq],kind:row[kind],payload:json.loads(row[payload])}forrowinrows]运行输出模块定义成功无标准输出乐观并发不是可选装饰expected_seq看似多余却是避免“丢失推进”的关键。两个 worker 同时读到序号 2都想写序号 3复合主键只允许一个成功另一个收到IntegrityError后必须重新加载历史。不能用SELECT MAX(seq)1后无条件插入并期待数据库替你排队因为读和写之间存在竞态。更不能发生冲突后自动改写成序号 4第二个事件的决策基于旧状态直接顺延会把过期决定伪装成合法新事实。下面保存为demo_102.py。它复用上一篇miniflow.Event写入四个事件然后故意用过期版本再次追加以证明冲突会被拒绝。为便于重复运行示例使用临时目录真实服务则传入固定路径。importsqlite3importtempfilefrompathlibimportPathfromevent_storeimportEventStorefromminiflowimportEventwithtempfile.TemporaryDirectory()asdirectory:pathPath(directory)/flow.dbstoreEventStore(str(path))workflow_idtrip-001seq0history[Event(trip_requested,{city:成都}),Event(budget_locked,{token:B-7}),Event(flight_booked,{ref:F-8}),Event(hotel_booked,{ref:H-9}),]foreventinhistory:seqstore.append(workflow_id,seq,event.kind,event.data)print(appended,seq,event.kind)try:store.append(workflow_id,2,hotel_booked,{ref:stale})exceptsqlite3.IntegrityError:print(stale writer rejected)loadedstore.load(workflow_id)print(order:,[row[kind]forrowinloaded])assert[row[seq]forrowinloaded][1,2,3,4]运行输出appended 1 trip_requested appended 2 budget_locked appended 3 flight_booked appended 4 hotel_booked stale writer rejected order: [trip_requested, budget_locked, flight_booked, hotel_booked]事务边界到底保护了什么当前append一次只写一个事件所以原子性看起来理所当然。真正的工作流引擎通常还要同时写待执行命令也就是 outbox。若先提交事件再写命令中间崩溃会得到“状态已推进、活动却永远没有调度”的孤儿状态若先发送网络请求再提交事件会得到“副作用成功、历史却说没发生”的幽灵执行。第四篇会把事件和 outbox 放入同一事务。本篇先把日志协议单独钉牢是为了分清存储正确性与投递正确性。非平凡踩坑是把 SQLite 的“数据库已提交”误解成“任何硬件故障都绝不丢”。可靠性仍受文件系统、磁盘缓存、挂载参数和备份方式影响。WAL 数据可能暂时位于-wal文件只复制主.db文件会产生不一致备份。在线备份应使用 SQLite backup API或者在受控 checkpoint 后复制完整文件集合。容器中还要确认数据库位于持久卷而不是随 Pod 消失的临时层。另一个记忆点是序号表达的是工作流内因果顺序不是全球时间。不要用自增整数比较两个不同工作流谁先发生也不要拿created_at做重放排序。同一工作流依赖复合主键的严格序号跨工作流统计可以使用时间但它只是观测维度。把业务因果和墙上时钟混为一谈遇到时钟回拨、批量导入或跨地域复制时会付出代价。为恢复准备输入本篇产出了event_store.py的EventStore.append与EventStore.load并得到一个含四条顺序事件的flow.db。数据库现在能记住发生过什么却还不会从日志恢复TripState。下一篇将直接读取load返回的字典列表重新调用上一篇的decide证明删掉所有内存状态后仍能精确恢复并进一步解决“重放时不能重复产生外部命令”的问题。 觉得有用就点个赞 收藏方便回头查阅有疑问直接在评论区留言我看到都会回。 文章里的代码都能直接跑。想要可直接 clone 的完整工程 配套部署脚本 / 踩坑清单评论一声或发邮件到cj2664qq.com我免费发你。如果你正好在做类似系统、或有工程化难题想找人做也欢迎邮件聊一句——我按实际情况评估能落地的就接单或出方案。评论和邮件都能直接找到我不用跳别的平台。

相关新闻

Cadence路径设置全解析:从环境变量到项目实战的EDA环境配置指南

Cadence路径设置全解析:从环境变量到项目实战的EDA环境配置指南

1. 项目概述:为什么Cadence路径设置是工程师的“第一课” 如果你刚接触Cadence这套庞大的EDA工具,或者在使用中频繁遇到“库找不到”、“工具启动报错”、“文件关联失败”这些问题,那么你大概率是卡在了“路径设置”这一关。这听起来像是个微…

2026/8/10 22:11:50 阅读更多 →
总线舵机通信协议、驱动板选型与实战避坑指南

总线舵机通信协议、驱动板选型与实战避坑指南

1. 从“单打独斗”到“集团军作战”:总线舵机为何是趋势 如果你玩过机器人、做过机械臂,或者捣鼓过一些需要精确动作的模型,那你肯定对舵机不陌生。传统的PWM舵机,就像一个个需要你亲自去喊话的士兵,每个舵机都独占一根…

2026/8/9 9:28:37 阅读更多 →
3句话,让AI帮我搞定一个App:谷歌“王炸”工具,正在让设计师和程序员一起失业?

3句话,让AI帮我搞定一个App:谷歌“王炸”工具,正在让设计师和程序员一起失业?

一行代码不用写,甚至不需要打开Figma,你的下一个UI设计师,可能真的会是AI。小伙伴们,今天分享一款谷歌“王炸”工具,打开网站点击立即试用!一句话生成设计稿“帮我设计一整套‘周末去哪儿’App,…

2026/8/15 10:13:57 阅读更多 →

最新新闻

开源项目第187期:Pi — 哲学驱动的极简 AI Coding Agent,86k Stars,30+ LLM 提供商,无限扩展

开源项目第187期:Pi — 哲学驱动的极简 AI Coding Agent,86k Stars,30+ LLM 提供商,无限扩展

引言 “Adapt pi to your workflows, not the other way around.” 这是「每日一个开源项目」系列的第 187 篇。今天的项目是 Pi —— 一个极简哲学驱动的 AI coding agent harness,86,334 颗 Star,由游戏开发者 Mario Zechner(libGDX 作者&a…

2026/8/15 14:04:09 阅读更多 →
SNMP Trap实战指南:从协议原理到Python代码实现

SNMP Trap实战指南:从协议原理到Python代码实现

1. 从一次深夜告警说起:为什么我们需要SNMP Trap?那天凌晨两点,手机突然震动个不停。不是电话,而是一连串的监控告警。我睡眼惺忪地抓起来一看,核心机房的某台交换机端口流量飙到了95%,眼看就要触发业务中断…

2026/8/15 14:04:09 阅读更多 →
Java基础复习08:File类、字节流、字符流、缓冲流、转换流、序列化、打印流、Commons-io包介绍

Java基础复习08:File类、字节流、字符流、缓冲流、转换流、序列化、打印流、Commons-io包介绍

目录一、File类与IO流概述1.1 文件路径的写法和相对路径1.2 File类对象的创建1.3 File类常用API1.4 文件搜索1.5 字符集的编码/解码1.6 IO流概述1.7 IO流的分类1.8 IO体系图二、字节流2.1 文件字节输入流(FileInputStream)创建对象与常用API每次读取一个字节int read()每次读取…

2026/8/15 14:04:09 阅读更多 →
DeepSeek Harness 开源:对标 Claude Code,v0.1 先尝鲜别上生产

DeepSeek Harness 开源:对标 Claude Code,v0.1 先尝鲜别上生产

8 月 13 日,DeepSeek 把自家 Agent 框架 Harness v0.1 以 MIT 协议开源了,GitHub 星数很快逼近 6 万。一句话概括这件事:这是一个"模型无关"的编程 Agent 框架,官方定位就是对标 Anthropic 的 Claude Code 和 OpenAI 的…

2026/8/15 14:04:09 阅读更多 →
DeepSeek V4 Pro 正式版上线:Agent 能力大涨,涨价也安排上了

DeepSeek V4 Pro 正式版上线:Agent 能力大涨,涨价也安排上了

8 月 13 日凌晨,DeepSeek 没开发布会,直接把官方 API 文档里的 V4 Pro 从预览版更新成了正式版 0813:调用名还是 deepseek-v4-pro,接口格式没变,存量代码一行都不用动。同一天,官方还放出了两个跟钱直接相关…

2026/8/15 14:04:09 阅读更多 →
网盘下载太慢太折腾?一个脚本搞定八大网盘直链下载

网盘下载太慢太折腾?一个脚本搞定八大网盘直链下载

网盘下载太慢太折腾?一个脚本搞定八大网盘直链下载 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云盘…

2026/8/15 14:03:09 阅读更多 →

日新闻

内景 空间站内部 中国空间站 太空 内仓

内景 空间站内部 中国空间站 太空 内仓

本项目为前几天收费帮学妹做的一个项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。 一、项目描述 空间站内部 中国空间站 太空 内仓 地址:本地PC端运行(或Web…

2026/8/15 0:00:30 阅读更多 →
重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能

重新定义数据接口:3个突破性场景让通达信数据读取更智能 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 当我们面对海量金融数据时,传统的数据获取方式往往让我们陷入困境—…

2026/8/15 0:00:30 阅读更多 →
一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

一文读懂快消WMS怎么选?2026年国内外10大主流WMS品牌盘点

快消品(FMCG)是流通速度较快、竞争较为激烈的行业之一。一瓶饮料从出厂到消费者手中,往往只有几十天甚至几天的周转窗口。这决定了快消行业的仓储管理系统(WMS)与制造业、电商行业存在明显区别:它不仅需要管…

2026/8/15 0:02:30 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/13 2:38:34 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/15 12:59:14 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/13 10:41:51 阅读更多 →

月新闻

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

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

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

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

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

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

2026/8/14 14:06:45 阅读更多 →
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/15 2:35:29 阅读更多 →