Skip to content

feat(scheduler): add complete run lifecycle APIs#320

Merged
innomentats merged 5 commits into
mainfrom
feat/v2-scheduler-runs
Jul 16, 2026
Merged

feat(scheduler): add complete run lifecycle APIs#320
innomentats merged 5 commits into
mainfrom
feat/v2-scheduler-runs

Conversation

@eetoc

@eetoc eetoc commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • give each scheduler.agent() invocation an independent project run identity
  • supervise complete Scheduler run lifecycles, including detached execution, cancellation, skipped runs, and terminal states
  • expose run, start, get, list, and stop Scheduler operations through the v2 Project API
  • migrate Scheduler CLI execution and inspection to the v2 run APIs while retaining existing observability commands
  • retain legacy Scheduler execution flags for CLI compatibility and report them as unsupported by complete Scheduler runs without declaring them deprecated

Validation

  • go test -count=1 ./cmd/agent-compose ./pkg/agentcompose/api ./pkg/storage/configstore
  • go test -race -count=1 ./pkg/loaders
  • go test -count=1 ./cmd/agent-compose -run 'TestCLISchedulerExecutionRejectsUnsupportedFlags|TestRunComposeSchedulerTriggerRejectsUnsupportedPrompt|TestNormalizeComposeSchedulerTriggerOptionsPayload|TestE2ECLIHelpCoversUserWorkflowCommands'
  • go build ./cmd/agent-compose
  • rebase range-diff confirms the original four Scheduler patches are unchanged from the previously validated branch

@monkeyscan

monkeyscan Bot commented Jul 16, 2026

Copy link
Copy Markdown

PR Title: feat(scheduler): add complete run lifecycle APIs

Commit: 9e8a242

本次PR增加了完整的调度器运行生命周期管理,核心变化包括:

  1. 调度器运行监管器 (scheduler_run_supervisor.go):新增 schedulerRunSupervisor,支持同步/异步启动调度器运行(Run/Start)、查询运行状态(Get/List)和主动停止(Stop)。它通过 context.WithCancelCause 实现取消传播,并在独立 goroutine 中执行运行。

  2. API 层 (project_scheduler_run_handler.go):新增 RunSchedulerStartSchedulerRunGetSchedulerRunListSchedulerRunsStopSchedulerRun 五个 RPC 接口,支持分页查询和游标编码/解码。

  3. CLI 层 (scheduler_runs.go):新增 scheduler runscheduler stop 命令,并统一了 scheduler trigger 的执行参数。scheduler run --detach 使用 StartSchedulerRun 实现异步启动。

  4. 存储层 (loader_run_page.go):新增按 loader 分页查询运行记录的能力,使用稳定的 (started_at, loader_id, run_id) 组合游标。

  5. 运行生命周期 (run_lifecycle.go):新增对 context.Cause 的检测,当运行被主动取消时,将状态标记为 canceled 而非 failed

  6. 项目代理运行ID (run_host_project_agent.go):提取并序列化项目代理调用ID,避免重复。

整体代码结构清晰,测试覆盖较充分,但存在个别可靠性和边界处理问题需要关注。

@monkeyscan

monkeyscan Bot commented Jul 16, 2026

Copy link
Copy Markdown

PR Title: feat(scheduler): add complete run lifecycle APIs

Commit: 08ab793

该 PR 是一个术语修正提交,将 CLI 中调度器运行相关 flag 的说明与错误信息里的 "Deprecated" 统一改为 "Unsupported for complete scheduler runs"。

修改范围:

  1. cmd/agent-compose/scheduler_runs.go:更新了 7 个 flag 的 usage 描述,重命名了内部错误函数 deprecatedSchedulerExecutionFlagErrorunsupportedSchedulerExecutionFlagError,并同步调整了局部变量名与错误文案。
  2. cmd/agent-compose/main_test.go:更新了测试断言字符串,并将测试函数名中的 Deprecated 改为 Unsupported。
  3. cmd/agent-compose/scheduler_runs_test.go:同样更新了测试断言、compose 文件名称及测试函数名。

整体评估:这是一次纯粹的消息/命名重构,行为未发生实质性变化。所有字符串替换在三个文件内保持一致,测试覆盖也同步跟进,未发现遗漏或编译风险。

@innomentats innomentats left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@innomentats
innomentats merged commit 936e43c into main Jul 16, 2026
16 checks passed
@innomentats
innomentats deleted the feat/v2-scheduler-runs branch July 16, 2026 14:19
RunID string `json:"run_id"`
}

func encodeSchedulerRunCursor(projectID, agentName string, run domain.LoaderRunSummary) string {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encodeSchedulerRunCursor 忽略 json.Marshal 错误,可能导致生成无效分页游标

encodeSchedulerRunCursor 在编码游标时使用了 payload, _ := json.Marshal(...) 忽略 json.Marshal 的错误。虽然当前结构体在正常情况下不会序列化失败,但如果未来字段发生变化(例如引入不可序列化的类型),base64.RawURLEncoding.EncodeToString 可能会收到 nil 或空字节切片,生成无效的空游标字符串,导致分页中断且难以排查。

Problem code:

Changed code at pkg/agentcompose/api/scheduler_run_cursor.go:21-25

Recommendation:
显式检查 json.Marshal 的错误,并在出错时返回空字符串或记录日志,避免静默生成无效游标:

payload, err := json.Marshal(...)
if err != nil {
return ""
}
return base64.RawURLEncoding.EncodeToString(payload)

}

func (s *schedulerRunSupervisor) Get(ctx context.Context, loaderID, runID string) (domain.LoaderRunSummary, error) {
if s.deps.Store == nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scheduler_run_supervisor.execute 未使用 defer 清理 goroutine,panic 时导致 channel 阻塞和资源泄露

execute 方法在 goroutine 中直接调用 s.deps.Execute,之后手动 close(active.done) 和 s.unregister。如果 Execute 发生 panic(或未来引入 panic recovery),active.done 不会被关闭,Run 和 Stop 调用者将永久阻塞在 <-active.done 上;同时该活跃运行记录也永远无法从 s.active 中移除,造成内存泄露。

Problem code:

Changed code at pkg/loaders/scheduler_run_supervisor.go:130-136

Recommendation:
在 execute 中使用 defer 确保 active.done 始终被关闭、unregister 始终被执行。例如:

defer cleanup()
defer close(active.done)
defer s.unregister(prepared.Run.ID, active)

或者使用 defer + recover 组合,捕获 panic 后将 active.err 设置为 panic 信息,再关闭 channel 和清理注册表。

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants