ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Gas Town Scheduler 架构:配置驱动的 polecat 容量调度与延迟派发机制

Gas Town Scheduler 架构:配置驱动的 polecat 容量调度与延迟派发机制 Gas Town Scheduler 架构配置驱动的 polecat 容量调度与延迟派发机制【免费下载链接】gastownGas Town - multi-agent workspace manager项目地址: https://gitcode.com/GitHub_Trending/ga/gastown导读Gas Town 是一个多智能体工作区管理器其内置的 Scheduler 组件解决了批量派发 polecat智能体执行单元时面临的背压back-pressure与容量控制问题默认情况下gt sling一次派发 N 个 beads 会同时拉起 N 个 polecat瞬间耗尽 API 速率限制、内存与 CPU。本文基于 docs/design/scheduler.md 及仓库源码完整讲解 Scheduler 的核心设计——通过scheduler.max_polecats一个配置项即可在「直接派发」与「延迟派发」两种模式间无感切换并深入剖析其 sling context bead 调度状态模型、DispatchCycle派发引擎、容量计算公式、熔断器与并发安全机制。读完本文你将掌握如何用三条命令启用容量控制、理解调度状态如何持久化在不污染工作 bead 的独立 ephemeral bead 上以及 daemon 心跳如何驱动增量派发。快速开始三步启用容量控制的延迟派发Scheduler 是配置驱动的不需要任何 per-command 标志位。只需设置scheduler.max_polecats配置项同一个gt sling命令就会自动适应派发模式# 1. 启用延迟派发配置驱动无需命令级标志 gt config set scheduler.max_polecats 5 # 2. 通过 gt sling 调度工作当 max_polecats 0 时自动延迟 gt sling gt-abc gastown # 单个任务 bead gt sling gt-abc gt-def gt-ghi gastown # 批量任务 beads gt sling hq-cv-abc # Convoy调度所有被跟踪的 issue gt sling gt-epic-123 # Epic调度所有子任务 # 3. 查看已调度的内容 gt scheduler status gt scheduler list # 4. 手动派发或让 daemon 自动派发 gt scheduler run gt scheduler run --dry-run # 先预览派发模式Dispatch Modesscheduler.max_polecats配置值完全决定派发行为值模式行为-1默认直接派发gt sling立即派发近零开销0直接派发与-1相同——gt sling立即派发N 0延迟派发gt sling创建 sling context bead由 daemon 派发这一语义在源码中有直接对应internal/scheduler/capacity/config.go中的SchedulerConfig.IsDeferred()方法返回c.GetMaxPolecats() 0而GetMaxPolecats()在配置缺失时回退到默认值-1直接派发。也就是说没有配置 直接派发老用户的既有工作流完全不受影响。常用 CLI 一览命令描述gt sling bead rigSling bead直接或延迟按配置gt sling bead... rig批量 sling/调度多个 beadsgt sling convoy-idSling/调度 convoy 中所有被跟踪的 issuesgt sling epic-idSling/调度 epic 的所有子任务gt scheduler status显示调度器状态与容量gt scheduler list按 rig 列出所有已调度的 beadsgt scheduler run手动触发派发gt scheduler pause全镇暂停所有派发gt scheduler resume恢复派发gt scheduler clear从调度器中移除 beads最小示例gt config set scheduler.max_polecats 5 gt sling gt-abc gastown # 延迟创建 sling context bead gt scheduler status # Queued: 1 total, 1 ready gt scheduler run # 派发 - 拉起 polecat - 关闭 context背景为什么需要调度器Scheduler 解决的是批量 polecat 派发的背压与容量控制问题。没有调度器时sling N 个 beads 会同时拉起 N 个 polecat耗尽 API 速率限制、内存和 CPU。调度器引入了一个调速器governorbeads 进入等待状态daemon 在遵守可配置并发上限的前提下增量派发它们。调度器作为step 14集成进 daemon 心跳流程——在所有智能体健康检查、生命周期处理和分支清理之后执行。这确保了系统在派发新工作之前是健康的Daemon heartbeat (every 3 min) | - Steps 0-13: 健康检查、智能体恢复、清理 | - Step 14: gt scheduler run (容量控制派发) | - flock (独占锁) - 检查暂停状态 - 加载配置 (max_polecats, batch_size) - 统计活跃 polecats (tmux) - 查询 sling contexts (bd list --labelgt:sling-context) - 与 bd ready 关联以确定未阻塞的 beads - DispatchCycle.Run() — plan execute report | - PlanDispatch(availableCapacity, batchSize, ready) | - 对每个计划的 bead: Execute → OnSuccess/OnFailure - 唤醒 rig 智能体 (witness, refinery) - 保存派发状态从源码看daemon 端通过子进程方式调用gt scheduler runinternal/daemon/daemon.go中的dispatchScheduledWork()使用exec.CommandContext以5 分钟超时执行命令并注入环境变量GT_DAEMON1标识 daemon 派发避免与手动派发混淆和BD_DOLT_AUTO_COMMIToff。派发门控条件是scheduler.max_polecats 0延迟模式。在internal/cmd/capacity_dispatch.go中isDaemonDispatch()通过检查GT_DAEMON 1来决定遇到锁冲突或暂停时是否静默跳过daemon 模式还是报错手动模式。Sling Context Beads调度状态的独立载体调度状态存储在上独立的 ephemeral beads上称为sling contexts。工作 bead 永远不会被调度器修改——这是整个设计最核心的不变量。每个 sling context bead 具备以下特征通过bd create --ephemeral创建带标签gt:sling-context有一个tracks依赖指向工作 bead所有调度参数以 JSON 形式存储在 description 中在派发成功、bead 被 clear、或熔断器跳闸时关闭为什么用独立 beads之前的方案在工作 bead 的 description 上存储调度元数据分隔块并用标签gt:queued作为状态信号这需要两步写入 回滚先元数据后标签description 净化以避免分隔符冲突三步派发清理剥离元数据 交换标签 重试自定义 key-value 格式/解析/剥离函数约 250 行Sling context beads 消除了以上所有复杂性单一原子创建——bd create --ephemeral是一次操作JSON 格式——json.Marshal/json.Unmarshal替代自定义解析器工作 bead 保持原样——无 description 变更、无标签操作清晰的生命周期——open context 已调度closed context 已完成源码证据在 internal/beads/beads_sling_context.goCreateSlingContext()一次调用完成bd create --json --ephemeral --typetask --labelsgt:sling-context随后追加dep add --typetracks依赖此步骤非致命——即使依赖添加失败context bead 仍然创建成功CloseSlingContext()对already closed错误做幂等抑制保证重试安全。Context 字段JSON以下字段结构定义在 internal/scheduler/capacity/pipeline.go 的SlingContextFields结构体中序列化为 context bead 的 description字段类型描述versionintSchema 版本当前为 1work_bead_idstring被调度的实际工作 beadtarget_rigstring目标 rig 名称formulastring派发时应用的 formula如mol-polecat-workargsstring给执行器的自然语言指令varsstring换行分隔的 formula 变量keyvalueenqueued_atRFC3339调度时间戳mergestring合并策略direct、mr、localconvoystringConvoy bead ID自动创建 convoy 后设置base_branchstring覆盖 polecat worktree 的基础分支resume_branchstring恢复已有分支与base_branch互斥no_mergebool完成时跳过 merge queuereview_onlybool仅评审模式评估并汇报不 merge/commit/pushaccountstringClaude Code 账号句柄agentstring智能体/运行时覆盖如gemini、codexhook_raw_beadbool不带默认 formula 直接 hookownedbool调用方管理的 convoy 生命周期modestring执行模式ralph每一步使用全新上下文dispatch_failuresint连续失败计数熔断器last_failurestring最近一次派发错误信息其中dispatch_failures与last_failure是熔断器的核心计数器由recordDispatchFailure()在每次派发失败时更新见下文熔断器一节。Bead 状态机一个 sling context 的状态迁移如下------------------ | | v | ---------- dispatch ok -------- | schedule | CONTEXT | ---------------- | CLOSED | | -------- | OPEN | | (done) | | ---------- -------- | | | -- 3 failures -- CLOSED (circuit-broken) | -- gt scheduler clear -- CLOSED (cleared)状态表示触发条件SCHEDULEDOpen sling context beadscheduleBead()DISPATCHEDClosed sling contextreason: dispatcheddispatchSingleBead()成功CIRCUIT-BROKENClosed sling contextreason: circuit-brokendispatch_failures 3CLEAREDClosed sling contextreason: clearedgt scheduler clear关键不变量工作 bead 永不被调度器修改。所有状态都存在于 sling context bead 上。入口点Entry PointsCLI 入口点gt sling从配置和 ID 类型自动检测派发模式命令直接模式max_polecats-1延迟模式max_polecats0gt sling bead rig立即派发调度以便稍后派发gt sling bead... rig批量立即派发批量调度gt sling epic-idrunEpicSlingByID()——派发所有子任务runEpicScheduleByID()——调度所有子任务gt sling convoy-idrunConvoySlingByID()——派发所有被跟踪项runConvoyScheduleByID()——调度所有被跟踪项runSling中的检测链对应 internal/cmd/sling.go 与 internal/cmd/sling_schedule.goshouldDeferDispatch()——检查scheduler.max_polecats配置批量3 参数最后一个是 rig——runBatchSchedule()或runBatchSling()--on标志已设置——formula-on-bead 模式2 个参数且最后一个是 rig——scheduleBead()或内联派发1 个参数自动检测类型epic/convoy/task在 internal/cmd/sling_schedule.go 中shouldDeferDispatch()的判定逻辑是找不到 town 根目录则直接返回直接派发town settings 中无 scheduler 配置也返回直接派发只有当GetMaxPolecats() 0时才返回延迟派发。注意一个防御细节若 town settings 加载失败会返回错误并提示修复配置或使用gt config set scheduler.max_polecats -1——配置损坏会阻止派发而不是静默回退。所有调度路径都经过 internal/cmd/sling_schedule.go 中的scheduleBead()。 所有派发都经过 internal/cmd/capacity_dispatch.go 中的dispatchScheduledWork()。Daemon 入口点Daemon 在每次心跳step 14以子进程方式调用gt scheduler run// internal/daemon/daemon.go func (d *Daemon) dispatchScheduledWork() { ctx, cancel : context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() cmd : exec.CommandContext(ctx, gt, scheduler, run) cmd.Env append(os.Environ(), GT_DAEMON1, BD_DOLT_AUTO_COMMIToff) // ... }属性值超时5 分钟环境变量GT_DAEMON1标识 daemon 派发门控scheduler.max_polecats 0延迟模式调度路径Schedule PathscheduleBead()按顺序执行以下步骤校验bead 存在、rig 存在跨 rig 守卫——若 bead 前缀与目标 rig 不匹配则拒绝除非--force幂等性——若该工作 bead 已存在 open sling context 则跳过状态守卫——若 bead 处于 hooked/in_progress 则拒绝除非--force校验 formula——确认 formula 存在轻量无副作用烹饪 formula——bd cook在 daemon 派发前捕获坏的 protos构建 context 字段——SlingContextFields结构体携带所有 sling 参数创建 sling context——bd create --ephemeralbd dep add --typetracks原子操作自动 convoy——若未被跟踪则创建 convoy并将 convoy ID 存入 context 字段记录事件——为 dashboard 可见性发送 feed 事件创建是单一原子操作——无两步写入无需回滚。源码层面的细节值得展开幂等检查的位置scheduleBead()通过beads.ResolveRepoAliasBeadsDir()解析到目标 rig 的 beads 目录再用FindOpenSlingContext()查找已存在的 open context。找到则打印Bead %s is already scheduled (context: %s), no-op并直接返回。这一设计有一个关键历史背景GH#3468sling context 现在创建在目标 rig 的 beads 目录而非 HQ 的 beads 目录这样非 HQ rig 的 witness 才能在 patrol 中发现它。状态守卫的纵深防御scheduleBead()还会拒绝 closed/tombstone 状态的 beadbead %s is %s (work already completed)且这一守卫不受--force绕过——如果需要重新派发必须先 reopen 该 bead。这是为了防止 daemon 的 stranded 扫描把已完成的跨前缀 bead 重新调度生成幽灵 convoy。formula 的解析顺序resolveFormula()显式--formula标志 → rig property layersgt rig config set rig default_formula mol-evolvewisp 层--global则到 bead 层→ rig settings 文件workflow.default_formula→ 硬编码回退mol-polecat-work。派发引擎Dispatch EngineDispatchCycle派发循环是一个注入回调的通用编排器type DispatchCycle struct { AvailableCapacity func() (int, error) // 空闲派发槽位0无限 QueryPending func() ([]PendingBead, error) // 有资格派发的工作项 Execute func(PendingBead) error // 派发单个项 OnSuccess func(PendingBead) error // 派发后清理 OnFailure func(PendingBead, error) // 失败处理 BatchSize int SpawnDelay time.Duration }Run()内部调用PlanDispatch(availableCapacity, batchSize, ready)决定要派发什么然后通过回调执行每个计划项。该类型定义在 internal/scheduler/capacity/dispatch.go。源码级增强细节DispatchCycle还支持可选的Validate预派发钩子——返回非 nil 错误会短路该 bead 的派发不调用Execute直接调用OnFailure。这用于快速不变量检查如跨 rig 前缀守卫它不消耗失败配额也不会触发昂贵的派发机制。另一个重要实现细节是OnSuccess 的重试机制onSuccessRetries 2RunPlan()中OnSuccess失败会以递增间隔attempt1* 500ms重试最多 3 次若仍失败则该 bead不计入 Dispatched而是作为失败处理ErrOnSuccessFailed防止下一周期重复派发。ErrOnSuccessFailed专门用来区分polecat 已启动但 context 关闭失败与polecat 从未启动两种情况。派发流程DispatchCycle.Run() | - AvailableCapacity() → capacity maxPolecats - activePolecats | - QueryPending() → getReadySlingContexts(): | - bd list --labelgt:sling-context --statusopen (所有 rig DBs) | - 解析每个 context bead description 的 SlingContextFields | - bd ready --json --limit0 (所有 rig DBs) → readyWorkIDs 集合 | - 过滤WorkBeadID 在 readyWorkIDs 中的 context beads | - 跳过熔断的dispatch_failures 阈值 | - PlanDispatch(capacity, batchSize, ready) | - 返回 DispatchPlan{ToDispatch, Skipped, Reason} | - 对每个计划的 bead - Execute: ReconstructFromContext(fields) → executeSling(params) - OnSuccess: CloseSlingContext(contextID, dispatched) - OnFailure: 递增 dispatch_failures、更新 context、必要时关闭 - sleep(SpawnDelay)源码级增强细节getReadySlingContexts()的实现在 internal/cmd/capacity_dispatch.go比文档中的伪代码更精细——它先通过assessScheduledContexts()对每个 open context 做批量评估按enqueued_at排序FIFO先调度先派发批量获取工作 bead 状态batchFetchBeadInfoByIDs使用bd show --json按 beads 目录分组批量查询避免对大型仓库执行 O(minutes) 的bd list --all再通过bd blocked --json查询阻塞状态。一个 bead 被视为 ready 的条件是工作 bead 存在、未被阻塞、状态为 open。此外派发管线中有两道针对消息类标签的防御过滤引用自 gt-el4 事件gt:message、gt:handoff、gt:merge-request标签的 beads 是智能体间通信工件绝不能交给 polecat 派发。capacity.IsMessagingBead()与FilterMessagingBeads()定义在 internal/scheduler/capacity/pipeline.go在PlanDispatch的容量计算之前就做防御性剔除readySlingContextsFromAssessments()在查询端也做同样的检查。dispatchSingleBead大幅简化——context 字段已经解析完毕ReconstructFromContext(b.Context)→DispatchParams其中BeadID b.WorkBeadID调用executeSling(params)——就这些派发后的清理由回调处理OnSuccessCloseSlingContext(b.ID, dispatched)OnFailure递增dispatch_failures、更新 context bead、若熔断则关闭ReconstructFromContext()的实现internal/scheduler/capacity/pipeline.go把 JSON 字段还原为DispatchParams其中vars字符串按换行拆分回[]string。dispatchSingleBead()随后把这些参数组装成SlingParams调用executeSling()并设置FormulaFailFatal: true、NoConvoy: true、NoBoot: true以及CallerContext: scheduler-dispatch——保证调度器派发时的行为一致性与幂等性。容量管理Capacity Management配置项键类型默认值描述scheduler.max_polecats*int-1最大并发 polecats-1直接0禁用N延迟scheduler.batch_size*int1每次心跳 tick 派发的 beads 数scheduler.spawn_delaystring0s两次 spawn 之间的延迟避免 Dolt 锁竞争通过gt config set设置gt config set scheduler.max_polecats 5 # 启用延迟派发 gt config set scheduler.max_polecats -1 # 直接派发默认 gt config set scheduler.batch_size 2 gt config set scheduler.spawn_delay 3s源码级细节SchedulerConfig定义在 internal/scheduler/capacity/config.go是一个全镇级town-wide设置而非 per-rig——因为 API 速率限制、内存和 CPU 是所有 rig 共享的宿主级资源。GetMaxPolecats()、GetBatchSize()、GetSpawnDelay()都在字段缺失时回退到默认值-1、1、0sParseDurationOrDefault()对非法时长字符串同样回退到 fallback。scheduler run --batch N可在运行时覆盖 batch_sizebatchOverride 0时生效。派发数量公式toDispatch min(capacity, batchSize, readyCount) 其中 capacity maxPolecats - activePolecats正数 空闲槽位数0 或负数 无容量 batchSize scheduler.batch_size默认 1 readyCount 工作 bead 出现在 bd ready 中的 sling context 数PlanDispatch()是这一公式的纯函数实现internal/scheduler/capacity/pipeline.go它会返回一个DispatchPlan{ToDispatch, Skipped, Reason}其中Reason精确标识本次限制因素capacity容量不足、batch达到批次上限、ready就绪数量不足、none无就绪 bead。dry-run 模式下这些原因会直接展示给操作员。活跃 Polecat 计数活跃 polecat 通过扫描 tmux 会话并调用session.ParseSessionName()匹配角色来统计countActivePolecats()在 internal/cmd/scheduler.go。这会统计所有polecat——包括调度器派发的和直接 sling 的——因为 API 速率限制、内存和 CPU 是共享资源。在派发主路径上实际用于容量准入的是更精细的polecatCapacitySnapshotForTown()它区分 working、recovery_blocked、reservations、reusable_idle、pending_mr 等状态gt scheduler status会把这些细分维度完整展示出来。熔断器Circuit Breaker熔断器防止永远失败的 beads 导致无限重试循环。属性值阈值maxDispatchFailures 3计数器sling context JSON 中的dispatch_failures字段跳闸动作关闭 sling contextreason: circuit-broken重置无自动重置需人工干预流程派发尝试失败 | - 递增 context bead 中的 dispatch_failures - 存储 last_failure 错误信息 | - dispatch_failures 3? - 是 - CloseSlingContext(contextID, circuit-broken) | context bead 关闭工作 bead 不受影响 - 否 - bead 保持已调度状态下一周期重试源码级细节maxDispatchFailures 3定义在 internal/cmd/capacity_dispatch.go。recordDispatchFailure()递增计数并记录错误达到阈值后关闭 context。熔断逻辑在派发管线中有三重防线cleanupStaleContexts()在派发周期开始前就会关闭已熔断的 contextreason: circuit-broken以及无效 contextinvalid-context和工作 bead 已 stale 的 contextstale-work-bead如 hooked/closed/tombstonein_progress 有意排除——工作 bead 正在被积极处理bd ready不会返回它派发查询已天然防止重复派发。assessScheduledContexts()在收集候选时跳过DispatchFailures maxDispatchFailures的 context。capacity.FilterCircuitBroken()作为纯函数提供最终的过滤工具。另外PlanDispatch的失败策略在纯函数层有抽象CircuitBreakerPolicy(maxFailures)返回达到阈值前重试、之后隔离的策略NoRetryPolicy()则首次失败即隔离。调度器控制Scheduler ControlPause / Resume暂停会全镇停止所有派发。状态存储在.runtime/scheduler-state.json。gt scheduler pause # 设置 pausedtrue记录操作者与时间戳 gt scheduler resume # 清除暂停状态写入是原子的临时文件 重命名防止并发写入者造成损坏。源码级细节SchedulerState结构体定义在 internal/scheduler/capacity/state.go包含Paused、PausedBy、PausedAt、LastDispatchAt、LastDispatchCount字段。LoadState()在文件不存在时返回零值状态有意设计缺失 未暂停、从未派发并支持从旧的queue-state.json迁移SaveState()采用os.CreateTempos.Rename的原子写入。文档强调的fresh state on save在 internal/cmd/capacity_dispatch.go 中落地为派发完成后重新读取状态再写入RecordDispatch()避免覆盖并发 pause 操作。Clear关闭 sling context beads将 beads 从调度器中移除gt scheduler clear # 关闭 ALL sling contexts gt scheduler clear --bead gt-abc # 关闭特定 bead 的 context源码级细节--bead变体会扫描所有rig 目录下的 contexts因为 context 存在于目标 rig 的 beads 目录GH#3468并关闭该工作 bead 对应的全部context处理并发scheduleBead竞态可能产生的重复 context。Status / Listgt scheduler status # 摘要paused、queued 数量、活跃 polecats gt scheduler status --json # JSON 输出 gt scheduler list # 按目标 rig 分组的 beads带阻塞指示符 gt scheduler list --json # JSON 输出list将 sling contexts所有已调度项与bd ready未阻塞的工作 beads对账以标记阻塞的 beads。status --json输出paused、paused_by、queued_total、queued_ready、active_polecats、capacity、last_dispatch_at等结构化字段便于脚本消费。调度器与 Convoy 的集成Convoys 和调度器是互补但不同的机制。Convoys 跟踪相关 beads 的完成情况调度器控制派发容量。派发 convoy 工作有两条路径派发路径路径触发容量控制使用场景直接派发gt sling convoy-idmax_polecats-1无立即触发默认模式——所有 issues 一次性派发延迟派发gt sling convoy-idmax_polecats0有daemon 心跳、max_polecats、batch_size容量控制——批量 背压直接派发max_polecats-1gt sling convoy-id调用runConvoySlingByID()通过executeSling()立即派发所有 open 的被跟踪 issues。每个 issue 的 rig 从其 bead ID 前缀自动解析。无容量控制——所有 issues 同时派发。延迟派发max_polecats0gt sling convoy-id调用runConvoyScheduleByID()调度所有 open 的被跟踪 issues创建 sling context beads。Daemon 通过gt scheduler run增量派发遵守max_polecats和batch_size。对于同时派发会耗尽资源的大批量任务请使用此模式。何时用哪种小 convoy 5 个 issues直接派发默认max_polecats-1大批量5 个 issues设置scheduler.max_polecats以启用容量控制派发Epics同样的逻辑——gt sling epic-id从配置自动解析模式Rig 解析gt sling convoy-id和gt sling epic-id通过beads.ExtractPrefix()beads.GetRigNameForPrefix()从每个 bead 的 ID 前缀自动解析目标 rig。Town 根 beadshq-*会被跳过并给出警告因为它们是协调工件而非可派发的工作。detectSchedulerIDType()的类型检测顺序为hq-cv-前缀快速路径 → bead 的IssueTypeepic/convoy→ 标签gt:epic/gt:convoy→ 回退为 task。注意 convoy/epic 模式下会校验不允许使用 task-only 标志--account、--agent、--ralph、--args、--var、--merge、--base-branch、--no-convoy、--owned、--no-merge、--review-only。安全属性Safety Properties属性机制调度幂等性若工作 bead 已存在 open sling context 则跳过工作 bead 保持原样调度器从不修改工作 bead 的 description 或标签跨 rig 守卫若 bead 前缀与目标 rig 不匹配则拒绝除非--force派发串行化flock(scheduler-dispatch.lock)防止双重派发原子调度单次bd create --ephemeral——无两步写入无回滚formula 预烹饪调度时bd cook在 daemon 派发循环前捕获坏的 protos保存时读取最新状态派发在保存前重新读取状态避免覆盖并发 pause源码级细节跨 rig 守卫有两层。调度时checkCrossRigGuard()除非--force派发时validatePendingBeadForDispatch()调用capacity.AcceptsPrefix()检查前缀匹配定义于 internal/scheduler/capacity/dispatch.go。若 rig 前缀未知空退化为接受开放降级而非拒绝派发。派发层发现跨 rig 前缀不匹配会打印告警并触发gt escalateMEDIUM 级别告警带 1 小时防抖防止每个心跳 tick 都刷屏。派发串行化dispatchScheduledWork()使用gofrs/flock对.runtime/scheduler-dispatch.lock做TryLock()。daemon 模式下拿不到锁则静默返回 0下个周期再试手动模式则报错dispatch already in progress。派发循环的不变量校验若计划有ToDispatch但Dispatched 0 Failed 0直接返回scheduler dispatch invariant violation错误——这是对派发逻辑正确性的运行时断言。代码布局Code Layout路径用途internal/scheduler/capacity/config.goSchedulerConfig类型、默认值、IsDeferred()internal/scheduler/capacity/pipeline.goPendingBead、SlingContextFields、PlanDispatch()、ReconstructFromContext()internal/scheduler/capacity/dispatch.goDispatchCycle类型——通用派发编排器internal/scheduler/capacity/state.goSchedulerState持久化internal/beads/beads_sling_context.goSling context CRUDcreate、find、list、close、updateinternal/cmd/sling.goCLI 入口、配置驱动的路由internal/cmd/sling_schedule.goscheduleBead()、shouldDeferDispatch()、isScheduled()internal/cmd/scheduler.gogt scheduler命令树internal/cmd/scheduler_epic.goEpic 调度/sling 处理器internal/cmd/scheduler_convoy.goConvoy 调度/sling 处理器internal/cmd/capacity_dispatch.godispatchScheduledWork()、派发回调接线internal/daemon/daemon.go心跳集成gt scheduler run架构上值得注意的是internal/scheduler/capacity包刻意保持为纯函数与类型调度循环、入队、epic/convoy 解析等不纯的编排逻辑留在 cmd 层这使得PlanDispatch、FilterCircuitBroken、CircuitBreakerPolicy等核心决策函数易于单元测试。延伸阅读Convoys——Convoy 跟踪、调度时的自动 convoy 创建Property Layers——调度器标签使用的 labels-as-state 模式见 Operational State Events 章节调度派发作为 daemon 心跳 step 14 运行其上游是 daemon 心跳的完整健康检查链docs/design/ 目录下的 watchdog 相关设计文档以上所有源码路径与配置示例均以当前仓库为准。若需在本地复现本文示例请先在已初始化的 Gas Town town 目录内执行gt config set scheduler.max_polecats N后运行gt scheduler status观察状态变化并使用gt scheduler run --dry-run在真实派发前预览计划。【免费下载链接】gastownGas Town - multi-agent workspace manager项目地址: https://gitcode.com/GitHub_Trending/ga/gastown创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进