
OpenMuse 持久化任务引擎原理SQL 租约、检查点与中断恢复如何做到任务永不丢失【免费下载链接】openmuseA personal agent with a browser, terminal, files, and work that keeps going built with CopilotKit and AG-UI.项目地址: https://gitcode.com/gh_mirrors/op/openmuseOpenMuse 是一个自带浏览器、终端、文件和持续工作的个人智能体基于 CopilotKit 与 AG-UI 构建。它的持久化任务引擎把每个任务的状态、租约和检查点都写入 SQL 数据库即使进程崩溃、服务器重启或任务被暂停工作也不会丢失——这就是任务永不丢失的核心承诺。为什么个人智能体的任务容易丢大多数智能体的工作是对话式的你发消息它回复对话结束状态就留在内存里。一旦进程重启正在执行的任务、执行到一半的步骤、已经保存的中间结果全部蒸发。OpenMuse 的解决思路很直接任务不是内存对象而是数据库记录。所有任务tasks、监控monitors、事件run-events都落在一张records表里用 JSONB 存储配合乐观锁Compare-And-Swap保证多 worker 并发下的正确性UPDATE records SET data data || $patch::jsonb WHERE owner$1 AND kind$2 AND id$3 AND data $expected::jsonb RETURNING data这段 SQL 是整台引擎的基石——只有当我看到的数据和我预期的完全一致时才更新实现了无锁的并发控制。实现见 db.ts。第一步任务入队即持久化当你委派一个任务时服务端并不是启动一个内存协程而是先往数据库插入一条AgentTask记录初始状态queued。任务的完整生命周期状态定义在 agent.ts状态含义queued排队等待 worker 领取running某个 worker 持有租约正在执行scheduled定时任务等待nextRunAt到期waiting_input/waiting_approval等你补充信息或批准动作paused/succeeded/failed/cancelled暂停 / 终态任务创建入口在 service.ts注意新建任务时leaseId和leaseUntil都初始化为null——没有租约的任务永远处于可被安全领取的状态。核心机制一SQL 租约Lease——谁持有任务说了算后台的 TaskWorker 每秒扫描一次任务表找出到期任务queued、scheduled到点、running但租约已过期、waiting_approval然后用一次 compare-and-swap 原子地抢占任务生成唯一的leaseIdUUID写入leaseUntil now 60s状态置为runningattempts 1关键代码在 worker.ts。抢占的期望条件包含旧的leaseId和旧的leaseUntil意味着两个 worker 同时抢同一个任务只有一个能成功CAS 天然互斥租约过期后任务自动变回可领取——这就是崩溃 worker 的兜底。持有任务后worker 还会启动一个心跳定时器间隔为租约时长的一半约 20 秒不断续期leaseUntilworker.ts。如果心跳的 CAS 失败——说明任务被暂停、取消或被别的 worker 接管——当前执行会被立即abort不再写任何数据。核心机制二检查点Checkpoint——每走一步就存档一次任务执行函数execute拿到的不是一个裸状态而是一个TaskContext其中checkpoint(patch)方法worker.ts做两件事验证租约仍在自己手里CAS 条件里带leaseId失败就抛出LostLeaseError把中间进度state、evidence、plan、artifactIds等合并写回数据库。以文档填写任务为例找到源 PDF 后立即 checkpointservice.ts填完表单生成副本后再 checkpointservice.ts。这意味着即使进程在准备回复邮件这一步被杀掉下次恢复执行时直接从数据库读回PDF 已找到、副本已生成的状态不会重复下载或重复填写。执行中的每个关键节点还会写一条不可变的RunEvent记录最终在任务详情页按时间线回放给用户service.ts。核心机制三中断恢复——崩溃、重启、被接管之后怎么办引擎把执行中断分成两类处理worker.ts① 租约丢失优雅中断任务被用户暂停/取消、或已被别的 worker 接管。此时不记错误只是把状态改回queued并清空租约——任务毫发无损随时可以被再次领取。② 真实执行错误记录一条error事件状态置failed并保存错误详情同时把本次runs记录标记为interrupted/failed。用户可以在界面上直接重试。③ 进程级重启最硬的场景正在running的任务租约必然过期下一轮 tick 会被新 worker 重新领取从最近的 checkpoint 继续启动时 recoverInterruptedActions() 会把卡在executing的敏感动作批量标记为outcome_unknown防止邮件可能已发出也可能没发出的歧义被静默吞掉每 60 秒一次的 maintain() 维护循环负责善后对账补发漏掉的通知、复活被中断的监控任务、修复已接受但任务未创建的 Ideas。这套机制的验收证据记录在 docs/VERIFICATION.md真实的 PGlite 重启、双 worker 租约竞争、过期租约恢复、暂停/恢复、审批公平性等场景都有自动化测试覆盖。完整生命周期一图流创建任务 ──▶ queued入库 │ worker tick 每秒扫描 │ CAS 抢占成功写入 leaseId leaseUntil ▼ running ──心跳续租~20s──▶ checkpoint 存档 ──▶ 完成succeeded │ │ 租约丢失/被接管 ──▶ 回 queued 等待重领 真实错误 ──▶ failed 错误事件 │ 进程崩溃 ──▶ 租约过期 ──▶ 下一个 worker 重新领取从检查点继续动手阅读源码存储层与乐观锁db.ts租约、心跳与恢复worker.ts任务编排与检查点示例service.ts任务状态机定义packages/domain/src/agent.ts功能总览与验收记录docs/FEATURES.md、docs/VERIFICATION.md一句话总结OpenMuse 的永不丢失不靠运气而是靠三条纪律——状态永远在数据库里、写入必须带租约校验、恢复必须从检查点开始。理解了这三点你就理解了绝大多数可靠任务系统的骨架。【免费下载链接】openmuseA personal agent with a browser, terminal, files, and work that keeps going built with CopilotKit and AG-UI.项目地址: https://gitcode.com/gh_mirrors/op/openmuse创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考