myxce/docs/left_scheduler_work.md
lei.chen c90e63ec0f fix(frontend): job control no longer returns HTTP 500 (bug-1490)
Two stacked defects in the apiserver job-control link, both of which kept
hold/release/cancel from ever reaching the controller:

1. controllers/jobs.go: validateJobControl and foundJob asserted
   jobinfo.Data["array_idx"].(int64), but StoreToOrderMaps produces
   array_idx as int (models.JobInfo.ArrayIdx is declared int) -> panic
   -> Gin Recovery -> HTTP 500 before backend.ControlJob ran. Add
   normalizeJobInt64 / jobArrayIdx helpers and use them in both
   functions (job_status already had this fix via normalizeJobStatus;
   array_idx was missed).

2. backend/clib.go: backend.ControlJob set xce_jobctrl_t.action to the
   models.JOB_* constant (JOB_STOP=1 / JOB_RESUME=2 / JOB_KILL=3 /
   JOB_CHKPNT=8), but that field is the capnp JobControl union
   discriminant (JobControl_u_siginfo=0 / JobControl_u_ckptoption=1).
   The controller's job_ctrl() selected the wrong union branch (or
   none, since encode_JobControl drops the union pointer for
   non-0/1 discriminants) and rejected every control with -EINVAL.
   Add jobCtrlDiscriminant() and use it.

Also: resolveExecUser was defined in the cgo-only convert.go but is
exercised by a non-cgo test, so `make test` (CGO_ENABLED=0) failed to
build the backend package. Move it to convert_pure.go so it compiles in
both modes.

Tests: 3 controller regression tests (validateJobControl allowed /
not-allowed branches, foundJob array-child branch) + 1 backend
jobCtrlDiscriminant test. make test fully green. Cluster E2E verified:
hold -> PSUSP, release -> PEND, cancel -> EXIT on a PEND job, no 500,
no -EINVAL, all daemons healthy.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-07 07:35:51 +00:00

196 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scheduler 剩余工作清单(left_scheduler_work)
- 状态:持续更新
- 日期:2026-08-07
- 来源:项目自带 MD 设计文档分析(.kiro/steering、.kiro/specs、docs/、CLAUDE.md)
本文汇总 scheduler 相关的一切剩余/未完成/已知损坏的工作,按优先级排序。每项标注来源文档与状态。
---
## 一、最紧急:当前影响集群的 bug
### 1. bug-1494 — 作业全部 PEND 不调度【根因已定位,2026-08-07】
- **状态**:未解决(根因已定位)
- **来源**:`CLAUDE.md`、`docs/Scheduler-Agent-设计文档.md` §10.2b
- **根因(实证确认)**:controller 重启后,worker + scheduler **都不能自愈重连**,导致 scheduler 资源视图 slots=0 → 无法派发:
1. **worker 不重连**:controller 重启后 t1 保持 `UNAVAIL`(NCPUS/MAX_SLOT=-,HOST_TYPE=UNKNOWN),每 15s `Failed to send load indices error -1`,无 rejoin 尝试(worker 连接监控 `checking_connection` 未检测到 controller 重启)
2. **scheduler 无重连逻辑**:controller 重启后 scheduler 连接断开,重启后重新 join 时看到 t1 UNAVAIL、0 slots(`resource 0 (slots) total 0.000000 shortfall 1.0`)
3. scheduler 无法分配 → 全部 PEND(`main decision = (nil)`)
- **已排除**:不是 wbuf 污染(bug-1508 修复无效);不是 resources.yaml(缺 slots 定义但 slots 是内置资源,来自 host config `mxj`/`maxcpus`)
- **关联**:component-failover-adoption(scheduler 重连)+ worker 连接监控健壮性——**这是 P2.5/component-failover-adoption 的核心,尚未实现**
- **临时恢复**:全量重启 daemon(clean restart)可恢复,但集群无自愈能力
### 2. bug-1490 — apiserver control HTTP 500【已修复,2026-08-07】
- **状态**:已修复
- **来源**:`CLAUDE.md`、`Scheduler-Agent-设计文档.md` §10.2b
- **根因(两个叠加缺陷)**:
1. **array_idx 类型断言 panic → HTTP 500**:`validateJobControl`/`foundJob` 用 `jobinfo.Data["array_idx"].(int64)`,但 `StoreToOrderMaps` 产出的是 `int`(`JobInfo.ArrayIdx` 声明为 `int`)→ panic → Gin Recovery → HTTP 500 → 请求到不了 controller。
2. **jobctrl 联合判别符错误 → -EINVAL**:`backend.ControlJob` 把 `xce_jobctrl_t.action` 设成 `models.JOB_*`(1/2/3/8),但该字段是 capnp `JobControl` union 判别符(`JobControl_u_siginfo=0`/`JobControl_u_ckptoption=1`)→ controller `job_ctrl()` 走错分支(default)→ 每个动作都 -EINVAL。
- **修复**:`normalizeJobInt64`/`jobArrayIdx` 辅助函数 + `jobCtrlDiscriminant` 映射。单测 5 个(controllers 3 + backend 1 + 顺带修了 pre-existing 的 backend cgo 测试编译)。集群 E2E 验证:hold→PSUSP、release→PEND、cancel→EXIT,无 500 无 -EINVAL,全部 daemon 健康。
- **顺带修复**:`resolveExecUser` 被放在 `//go:build cgo` 的 convert.go 里导致 `make test`(CGO_ENABLED=0)下 backend 包编译失败——移到纯 Go 的 convert_pure.go。
### 3. bug-1489 / bug-1491 — 已修复(上下文)
- bug-1491 OrderMap 列格式解析修复(2026-08-01,httpclient.go)
- bug-1489 whitelist 缺 `/xce/v1/apikeys` 修复(2026-08-01,middleware/whitelist.go)
---
## 二、scheduler-controller-msg-gap:已实现但有已知缺陷
spec 声称 36/36 任务完成,但 re-audit(research.md)发现缺陷。来源:`.kiro/specs/scheduler-controller-msg-gap/research.md`。
| 项 | 严重度 | 描述 |
|----|--------|------|
| **G-8** | HIGH | `sched_update_existing_job` 是死代码。notify 驱动的作业更新走 bulk `sched_update_jobs()` 的 CREATE 路径(make_sched_job 新建),损坏/复制作业状态。**很可能与 bug-1494 相关**。Req 3 UB-3.1/3.2 未满足。 |
| **G-3** | MED | 5 个新 op 的 payload(UPDATE_QUEUE/UPDATE_RESOURCES/UPDATE_RESVALS_FULL/UPDATE_RESVALS/JOB_RUSAGE)在 `sched_pend_update_killer` 里 `break;` 从不释放——长驻 daemon 慢速泄漏。 |
| **G-5** | MED | `xce_sched_job_t` 无 rusage 字段。JOB_RUSAGE case 只调插件 hook 就丢 payload。UB-6.1 未满足。 |
| **G-4** | LOW | 即使修好 G-8 让 `sched_update_existing_job` 可达,它也只在作业上应用 state——priority/queue/resreq 未应用。 |
| **G-6** | TODO | 任务 9.2/9.3/9.4/9.6/9.7 勾了 `[x]` 但测试缺失/部分;9.5 测的是本地 stub 非真 schedobj.c。 |
| **G-7** | TODO | 文档漂移:design 说 `xce_sched_op_name` 在 lib/helper,实际是 scheduler.c 里 static `sched_op_name`。 |
| **R-3** | 休眠 | Req 1 处理器前瞻实现,但 controller 当前不推送 Data_data_resources/resvals 表给 scheduler——生产未触发。 |
---
## 三、核心调度引擎重构(scheduler-framework 家族:spec 有、零实现)
来源:`.kiro/specs/scheduler-framework/`、`scheduler-core/`、`scheduler-allocation/`、`scheduler-preemption/`(均只有 requirements/brief,无 design/tasks)。roadmap 显示 "Next: /kiro-spec-requirements scheduler-framework"。
### scheduler-core(Phase 1-3)
| 项 | 描述 |
|----|------|
| 可插拔 picker 接口 | 替代硬编码 `"xce_sched_fcfs"` 字符串,`job_pick_plugin` 字段 + config 加载 + 每 queue 覆盖。核心循环调 `picker->next_job()`。 |
| `builtin_fcfs` 默认实现 | MUST/SHOULD hook 全实现,私有 ordq_t 状态,排序同现状(跨 queue priority desc,队内 priority desc + queue_time asc)。 |
| 无回归保证 | HA soak 必须验证作业挑选顺序零偏差。 |
| core/driver 分离 | 提取 `xce_sched_core_t`,无 mode flag,虚拟时钟 `xce_core_now()`,决策回调。Phase 2。 |
| 模拟模式 | JSONL/.replay 重放 + 虚拟时钟 + snapshot/restore + 确定性重放 + `xceadmin scheduler record` + `--sim/--sim-verify/--interactive`。Phase 3。 |
| 等价保证 | "记录实跑 → 模拟重放 → 决策字节级一致"(AC 7.1)。 |
### scheduler-allocation
| 项 | 描述 |
|----|------|
| 惰性 plan 迭代器 | `xce_alloc_plan_iter_t`:init(resreq)/next()->plan/fini(),cancel-safe。 |
| 惰性 host 迭代器 | `xce_host_iter_t`:init(plan, workers)/next()->worker,复用现有 select 表达式求值器。 |
| parjob 组合分配 | 替换 stub `return 0`:1host×N、2hosts×ceil(N/2)、…、Nhosts×1。 |
| 会话级 resreq 缓存 | keyed on {minTasks,maxTasks,select_node_id,rusage_hash,user,queue,project},作业 ingest 时预计算。 |
| seqjob 重包 | 1host/1slot 走同一迭代器接口,验证抽象。 |
### scheduler-preemption
| 项 | 描述 |
|----|------|
| `XCE_DECISION_PREEMPT` | decision.h 新 opcode + `xce_preempt_decision_t`(victim_jobids, SIGSTP, preempting_jobid)。 |
| victim 选择策略 | 默认 `"lowest_priority_first"`,LSF 式跨 queue(preemptible_queues),最小足够 victim 集,安全护栏(不抢占同/高优先级、非抢占 queue)。 |
| SIGSTP 管线 | scheduler→controller→worker→SIGSTP 进程组,作业→JOB_SUSPENDED,复用 HOOK_DETAIL_JOB_STOP。每 queue `preemptible/preempt_policy/preemptible_queues` 字段。 |
| 核心循环集成 | 分配失败后、pending 前:can_preempt → 选 victim → 发 PREEMPT → preempting 作业下一轮再派(异步抢占)。 |
| 后续推迟项 | SIGKILL+requeue 升级、JOB_SUSPENDED resume 机制。 |
---
## 四、故障转移 / 重连
### component-failover-adoption(14 任务全未勾选)
- **来源**:`.kiro/specs/component-failover-adoption/`
- **关键结论**:requirements.md Background 明确 "**scheduler 没有任何运行时重连/rejoin 逻辑**——连的 controller 死后,scheduler 无法切换到其他候选"。
- 任务 3.1:把 scheduler 的 per-candidate 循环换成单一 library 驱动的 connect/join + rejoin 回调。
- 任务 3.2:scheduler 多 controller join E2E 测试。
- Req 3:重连重试/backoff 不能阻塞 picker 线程(保持现有线程拆分)。
- Req 5:per-candidate 重连诊断日志(成功/不可达/standby 重定向)。
### P2.5
- **来源**:`product.md:35`、`docs/superpowers/plans/2026-05-07-p25-discovery.md`
- product.md 标 P2.5 "In progress";P2.5-6 描述 scheduler `--peers`/`--ca-cert` CLI 更新;P2.5-7(CGo bridge)推迟。是否全完成文档不确定。
- **注意**:P2.5 与 component-failover-adoption 用了两套技术路径(xce_connect_cluster 裸 endpoint vs xcecli_ctx_t/XCECLI_FAILOVER_CALL),文档未调和。
---
## 五、scheduler agent / MCP server(Phase 2-4)
来源:`docs/Scheduler-Agent-设计文档.md`
| 项 | 状态 | 描述 |
|----|------|------|
| Phase 2:SSE 事件流 | 计划 | apiserver SSE endpoint + EventBroker,schedulerclient `WatchJobs()`,mcp-server 接入。ADR-004 设计完成待实施。估 2-3 天。 |
| Phase 3:LSF adapter | 计划 | CLI 解析优先,Python Sidecar 后续。估 +1 月。 |
| Phase 4:Slurm + K8s | 计划 | slurmrestd + CLI fallback;client-go。估 +1 月。 |
| modify 工具 | 推迟 | apiserver 当前无 modify 端点(control 仅 kill/stop/resume/checkpoint),需新增后端端点。 |
| 未决决策 | 未解决 | LLM 模型选型(Claude API/自建/混合);多集群 URM 源识别;air-gapped LLM 访问。 |
---
## 六、roadmap / 加固项
| 项 | 状态 | 描述 |
|----|------|------|
| 调度决策过 commit barrier | 计划 | DISPATCH/PEND/PREEMPT 需过 majority commit barrier。多文档提及为独立加固项,从 scheduler-framework scope 推迟。 |
| worker-rejoin-resync | backlog | worker 重连重报运行/完成作业状态(bug-396 兜底)。依赖 ha-consistency-invariants。scheduler 间接受影响(恢复作业需调度状态核对)。 |
| entity-bearing snapshots | backlog | 解锁 config-upgrade-snapshot、基于快照的状态传输。影响 scheduler 模拟(snapshot/restore)。COW 机制存在但休眠。 |
| project-resource-ownership | 未来 spec | 层级项目树 + 资源配额,project-aware picker 插件,queue↔project 映射。核心循环零改动(只加新 picker)。 |
| perf-tuning-extraction / clusterconfig-schema-split | 计划 | 配置 schema 变更触及 scheduler 配置摄取。 |
| bulk job-array query/cancel | 推迟 | 依赖 job-array-single-wal-record。 |
---
## 七、文档空白(设计层面没人写过)
1. **调度决策 commit barrier 细节**——roadmap 只提了标题,无 spec/design。
2. **scheduler 状态在 controller failover 后如何同步**——全量重推?增量?文档沉默。roadmap:67 提到 lightweight rejoin re-attach(当前是 full-state rejoin,"大但罕见")。
3. **scheduler 模拟模式 vs controller WAL replay 关系**——failover 后 scheduler 从 controller WAL 重放还是收新状态推送?未讨论。
4. **core/driver 分离下的对象内存/生命周期**——三线程(picker/allocator/driver)async 生产者/消费者模型下借用指针的归属未细化。
5. **无 scheduler 专属 HA soak 测试**——多次提到 "HA soak regression" 但无 `/xce-test-ha` 变体专门跑 scheduler failover/reconnect。
6. **`src/scheduler/CLAUDE.md` 太薄**——约 25 行,无 spec 状态、无已知 bug 清单、无剩余工作节。建议补全(对照 `src/controller/CLAUDE.md`)。
7. **scheduler 与 raft/TLA+ 架构整合**——raft 系列落地后 scheduler 与 log/commit 模型的交互未讨论。
---
## 八、scheduler-agent(chatbot / AI 辅助)剩余工作
- 状态:持续更新
- 日期:2026-08-07
- 来源:`docs/Scheduler-Agent-设计文档.md`(v1.2,权威设计文档)、`src/docs/chatbot-verification.md`、`src/frontend/CLAUDE.md`、`CLAUDE.md`
- **注意**:feature 直接从设计文档实现,**未走 .kiro spec 流程**(`.kiro/specs/` 无 scheduler-agent/chatbot spec)。`/home/lchen/code/chatbot/` 是 XCE 完整镜像工作树,代码两份一致。
### 架构与现状
用户自然语言 → Claude Code(LLM)→ MCP stdio → mcp-server → schedulerclient → apiserver REST → controller(C 后端)。**不是独立聊天组件,而是自然语言调度管理 Agent 框架**。
**已完成**:
| Phase | 内容 | 状态 |
|-------|------|------|
| Phase 0 | 只读 MCP Server:6 读工具、schedulerclient、`mcp_readonly` 角色、API Key 认证 | ✅ 2026-07-26 |
| Phase 1 | 4 写工具(submit/cancel/hold/release)、`general_serial` 模板、`mcp_operator`、`dry_run` 审查 | ✅ 2026-08-01,submit E2E 验证,control 被 bug-1490 阻塞 |
代码:`src/frontend/mcp-server/`(10 工具,~1300 行)、`src/frontend/schedulerclient/`(45 测试)、apiserver API Key + RBAC 支持。
### 1. 阻塞性 bug(影响 chatbot E2E 验证)
| Bug | 影响 |
|-----|------|
| **bug-1490** | control(hold/release/cancel)HTTP 500,apiserver control 链路预存 bug,请求到不了 controller。**写工具 E2E 验证的头号拦路虎** |
| **bug-1494** | 作业全 PEND 不调度,Agent 提交流程无法完成。根因已定位(见第一节) |
### 2. Phase 2:监控 + 纠错闭环(未开始,估 2-3 天)
- **SSE 事件流**(ADR-004 设计已完、未实现):apiserver SSE endpoint + EventBroker,schedulerclient `WatchJobs()`,mcp-server 事件接入。Agent 工作流:submit → watch → analyze → auto-handle
- 3 个高级工具:`scheduler_analyze_failure`、`scheduler_suggest_resources`、`scheduler_estimate_wait_time`
### 3. Phase 3 / Phase 4:后端适配器(未开始)
- Phase 3:**LSF adapter**(CLI 解析优先,Python Sidecar 后续,估 +1 月)
- Phase 4:**Slurm**(slurmrestd)+ **K8s**(client-go)(估 +1 月)
### 4. 推迟 / 未决
- `scheduler_modify` 工具推迟——apiserver 当前无 modify 端点(control 仅 kill/stop/resume/checkpoint),需新增后端端点
- 3 个未决决策:LLM 模型选型(Claude API/自建/混合)、多集群 URM 来源识别、air-gapped LLM 访问
### 5. 设计层加固(文档已写、代码零实现)
- **Auto-pilot 模式**:用户显式授权范围内的自主行为
- **AI 操作审计日志**:每条操作记 `[timestamp] [user] [action] [params] [confirmed?]`
- **Golden test suite**:同一自然语言输入 → 同一工具调用序列的回归测试
---
## 建议优先级
1. **bug-1490**(apiserver control HTTP 500)——阻塞 chatbot 写工具 E2E,小而明确,能立即修。
2. **bug-1494**(作业 PEND)——根因已定位(worker+scheduler 不自愈)。G-8 死代码(scheduler 作业更新路径损坏)很可能是元凶。
3. **msg-gap G-8/G-3/G-5**——小而明确,能立即修。
4. **component-failover-adoption**(scheduler 重连)——与 bug-1494 的 join 链路疑点直接相关。
5. scheduler-agent Phase 2(SSE 事件流)——依赖 bug-1490/bug-1494 先修好。
6. scheduler-framework 重构——大规划,建议等前 5 项稳定后再动。