☰
OpenDots后台工作揭秘:AI同事如何在你离线时执行定时任务、暂停与重试全机制指南
2026/10/5 11:22:57 网站建设 项目流程

OpenDots后台工作揭秘:AI同事如何在你离线时执行定时任务、暂停与重试全机制指南

【免费下载链接】OpenDotsYour always-on AI coworkers that move between text, calls, and Slack.项目地址: https://gitcode.com/gh_mirrors/op/OpenDots

OpenDots 是一套开源的"常驻 AI 同事"(always-on AI coworkers)模板:每位 Dot 都有独立电脑,能在文字、通话和 Slack 之间切换协作。本篇揭秘它的后台工作(Background work)机制——AI 同事如何在你离线时按计划在服务端执行定时任务,以及暂停与重试是如何一步步生效的。全程无需大量代码,几分钟即可看懂这套调度、租约与恢复机制。

什么是 OpenDots 的"后台工作"

在 OpenDots 中,你可以给 AI 同事下达一条"以后也要做"的指令。系统会把它变成一条服务端定时回合:任务绑定在你原本的那段对话里,到点后由服务器自动替你的 Dot 跑一轮,你不需要开着页面。

官方在特性表中将其描述为:"Scheduled server-side turns in their original conversation, with pause and retry controls"(在原对话中按计划执行的服务端回合,附带暂停与重试控制)。入口和规则定义在 src/server/app.ts 的任务创建接口中:

  • 任务指令必须在3 到 4,000 字符之间;
  • 重复间隔最少60 秒,最长一年(interval校验见 src/server/app.ts);
  • 创建时必须选择归属对话,且工作区设置完整(Intelligence、模型等缺失时直接返回 503);
  • 若全局设置中关闭了研究权限,创建会被拒绝。

定时任务如何在你离线时执行

状态机:任务的六种生命周期

任务的数据模型定义在 src/shared/types.ts。每条任务始终处于六种状态之一:

queued(排队)→running(运行中)→completed(完成)/failed(失败)/paused(已暂停)/cancelled(已取消)

关键时间戳是nextRunAt:下次运行时刻。任务创建后进入排队状态,调度器到点领取;一次成功运行后,如果配置了重复间隔,系统会立刻算出下一次时间(nextRunAt = 现在 + 间隔),完成即排程,循环往复。

调度器:每秒一次的心跳

调度器 src/server/runner.ts 的逻辑非常朴素:start()之后每1 秒tick 一次;每次 tick 先问存储层"有没有到期任务",有就领取并执行,没有就安静等待。

注意 src/server/runner.ts 中的一个重要设计:只要当前已有任务在运行,tick 直接返回——同一时刻全系统只跑一个任务,按创建顺序串行排队,天然避免了并发冲突,也保护了模型与浏览器的配额。

租约(Lease):防止重复执行的保险丝

这是整个后台机制里最精妙的部分。当调度器领取任务时,src/server/store.ts 的claim()会:

  1. 生成一个唯一的租约 UUID,把任务标记为running,租约有效期180 秒(leaseUntil);
  2. 写入一条运行记录(run),状态running;
  3. 之后每次写回结果前,都先调用owns()校验"租约还是不是我的"——不是就拒绝写入。

这意味着:即使某个 worker 在运行中途崩溃、失联,超过 3 分钟租约到期后,下一次 tick 会把它安全地打回queued,备注"Previous worker lease expired; safely retrying"(见 src/server/store.ts),任务不会卡死,也不会被两个 worker 重复执行。

运行期间还有两道保险(src/server/runner.ts):

  • 每100 毫秒检查一次所有权,权限或租约一旦失效立即中止;
  • 单次运行超过90 秒硬性超时中止,防止某个网页或查询把队列拖死。

暂停机制:全局开关与逐任务控制

三个任务级动作

对每条任务,你可以随时下发三种动作:run(立即执行)、pause(暂停)、cancel(取消),定义见 src/shared/types.ts:

  • pause:任务状态直接改为paused,停止被调度,但保留全部历史,随时可再run;
  • cancel:标记cancelled,结束该任务的生命周期;
  • run:把任务重新放回队列,清空错误与下次时间,立即安排一轮新运行。而且它是幂等的——任务正在运行时再点run会原样返回,不会重复入队(见 src/server/store.ts)。

全局暂停开关

设置里有一枚总开关paused(src/server/store.ts)。它的影响是连锁的:

  • 开关打开后,调度器在领取阶段直接返回空——不再领取任何新任务;
  • 所有正在运行的任务被abortAll()中止,语音通话同样会被挂断(src/server/app.ts);
  • 反过来,关闭研究权限或修改记忆权限,也会让运行中的任务被打回队列"重新排队",等权限重新生效后按新规则执行。

权限变化时的即时熔断

服务端代理 src/server/dot-agent.ts 在运行期间每 100 毫秒对照一次"初始快照":如果 Dot 的角色、Space 授权、研究/记忆权限等任何一项被改动,当前回合立即中止。换句话说,你在网页上点了任何一个权限开关,正在跑的后台任务最多 100 毫秒内就会停下——这是"人始终拥有控制权"的直接体现。

重试与故障恢复:任务不会白跑

自动重试:租约过期即重排

如前所述,worker 失联导致的"假死"运行,会在租约到期后被自动打回队列安全重试,运行记录标记为interrupted并保留原因(src/server/store.ts)。

手动重试:从失败到重新排队

每次运行无论成败都会留下完整档案:Run记录(开始/结束时间、结果或错误)加上events事件流("Research worker started."、错误信息等,模型见 src/shared/types.ts)。失败任务会记下error文本与failed状态,你点一次run就能清空错误、重新入队。

优雅停机:重启后继续跑

服务退出走 src/server/shutdown.ts 的固定流程:先停调度器,再把进行中的任务释放回队列(备注"Server stopping; queued for restart"),最后带 8 秒截止线关闭平台与 HTTP 服务。结果就是:重启 OpenDots 后,之前没跑完的任务依然排在队列里,按原计划继续——你的 AI 同事不会因为服务器重启而"忘事"。

小结:一套小而完整的后台执行体系

机制行为定义位置
定时调度每秒心跳,串行领取到期任务runner.ts
租约保护180 秒有效期,过期安全重排store.ts
90 秒超时单次运行硬性上限runner.ts
暂停/取消/重试run / pause / cancel 三动作store.ts
权限熔断100 毫秒轮询,改动即中止dot-agent.ts
优雅停机运行中任务回队列,重启续跑shutdown.ts

OpenDots 的后台工作没有引入复杂的消息队列,而是用"SQLite + 状态机 + 租约"这套轻方案,把计划、暂停、重试、恢复四件事做扎实。想动手体验?克隆仓库后按 docs/SETUP.md 配置模型与 Intelligence,创建一条带间隔的任务,然后关掉浏览器——下次打开时,成果已经在你原来的对话里等你了。

【免费下载链接】OpenDotsYour always-on AI coworkers that move between text, calls, and Slack.项目地址: https://gitcode.com/gh_mirrors/op/OpenDots

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询