Skip to content

[Grok/dsh 46] 持久调度与重启行为 #178

Description

@Blackman99

Parent

#132

Ticket: 46

Status: ready-for-agent

User Stories: 46, 59, 62(见父规格)

What to build

用户显式选择持久调度后能在重启后继续管理它,非持久任务和已终止进程则保持各自真实语义。

Acceptance criteria

  • 持久化、到期、重启后下一次触发及错过触发的处理以固定版本实证为准,不擅自补跑外部副作用。
  • 多实例只能有一个触发所有者;重复启动、崩溃与删除竞争不造成重复已知任务。
  • 列表区分持久提示与不可恢复的进程,并清楚显示失败、停用和权限变化。
  • 用重启和受控时钟场景验证真实 dsh 调度,不宣称 exactly-once;记录无法判断的执行结果。

Blocked by

Delivery contract

用户于2026-09-20批准当前测试与任务拆分。按父规格的已安装产物/真实终端和公开协议测试验收;实际实现须带适用的文档、Changeset及必要检查。ready-for-agent表示任务已定义,不表示前置任务已完成,也不授权自动开始本轮实施、购买付费资源或发布软件版本。

Activity

  1. Blackman99 commented on Sep 25, 2026

    @Blackman99
    OwnerAuthor

    已在 rewrite/grok-dsh-20260920 实现:338e9c7

    实现内容

    • 循环按会话保存在 $DSH_HOME/codsh-schedules/<会话>.json(原子写入,文件权限 0600)。固定版本参考实现把所有调度状态放在会话的 resources 里,因此与参考一致,durable 和非 durable 循环都会保存,并在 --continue / --resume / /resume 时恢复。durable: true 只在有会话所有者时接受;没有所有者时以 scheduler_durability_unavailable 拒绝。
    • 错过的触发在恢复后只补触发一次(多个间隔合并为一次);已超过 7 天的循环直接移除,不触发。
    • 进程结束时仍在运行的触发记为 outcome unknown,不会重放;下一次触发会被告知上一次被中断,需先检查当前状态。整个设计不宣称 exactly-once。
    • 单一触发所有者:Rust 客户端持有会话所有者锁后,通过控制通道 schedule_owner 把锁 token 交给 dsh,dsh 在每次保存和触发前重新读取锁文件。锁变更(OWNER_LOST)或控制通道关闭(CLIENT_GONE)时,dsh 停止该会话的循环且不写文件。同一会话的第二个客户端会被拒绝。
    • 删除和 durable 到期要等“已移除”状态保存成功后才报告完成:保存失败时删除报错;durable 到期无法保存时循环保持暂停,不会复活。无法读取的文件保持原样,不被覆盖。
    • 列表行显示 saved / durable / not saved(详情里写明原因)、paused、最近一次触发失败或结果未知,以及权限模式与创建时不同时的 permissions changed。关闭子代理时,已保存的循环显示为暂停,可以删除。
    • 文档:帮助文本、README.md、README.zh.md、CONTEXT.md,以及 changeset rust-scheduled-restart.md(codsh-cli minor、codsh-bundle minor)。

    检查(真实计数,均在 rebase 到 #180/#183/#184 之后重新运行)

    • pnpm run typecheck:通过
    • TMPDIR=/tmp pnpm test:95 个文件,2478 通过 / 1 失败。失败的是已知的 reference-evidence.spec.mjs 5 秒超时,与本改动无关。
    • cargo fmt --check:通过
    • cargo clippy … -D warnings:只有 2 个既有错误(tail_marker 未使用、filesystem_sandbox.rs 多余的 return),没有新的 lint。
    • cargo test --workspace:1643 通过 / 4 失败 / 2 忽略。4 个失败都是既有的:2 个 filesystem_sandbox、privacy::drafts_stay_local…、voice::substitute_route…。
    • scripts/rust-scheduler.spec.mjs 共 28 项,已包含在上面的 pnpm test 中。其中有假时钟加临时目录的恢复、中断、到期、所有权、删除、损坏文件、暂停测试,以及真实 dsh 三次重启的集成测试:SIGKILL 后结果未知且不重放,另用 8 天偏移验证到期后移除且不触发。
    • PTY:
      • 新增的 rust-scheduler-restart-pty-test.py 通过,覆盖:退出后 --continue 补触发一次;第二个客户端被拒绝,且触发次数没有增加;SIGKILL 后没有残留 dsh,结果显示未知且不重放;在面板里删除后重启仍保持删除;--no-subagents 下显示暂停;权限变化会显示;8 天后到期移除且不触发。
      • rust-scheduler、background、subagent、workflow、queue 通过。
      • 仅限 macOS 的 resume、turn、cancel、shell、screen、nav 用临时副本在 Linux 上运行,全部通过。prompt 的副本只在已知的 CJK 换行检查处失败。

    未验证

    • macOS / Windows 没有运行。
    • 没有使用真实服务商,全部是无密钥的确定性 mock。
    • 本机没有安装参考二进制,也没有运行;持久化、到期、错过触发的行为依据的是固定版本源码(rev e8563f8,scheduler actor/registry 及其测试)。
    • 不宣称 exactly-once:被中断的触发只记为结果未知。

    main 分支、npm 发布和默认启动方式都没有改动;未 force-push,未发布。

    后续:正文引用 #178 的未关闭 issue 只有 #211(最终审计),它还有 25 个其他未关闭的依赖,因此本次没有解除阻塞的后续任务。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions