feat(apiserver): expose PEND reason end-to-end (scheduler → API)
The pending_reason field was declared on models.JobInfo but never populated:
scheduler computed PEND reasons and the controller stored them on
job->pend_reasons, yet the data stopped there. Two gaps closed:
1. controller/apiserver.c: apiserver_job_hook_fun now handles
HOOK_DETAIL_SETPREASON by pushing the updated job to API servers (reusing
apiserver_job_update_fun). Without this, a job whose PEND reasons change
never reached the API server — only JOB_NEW/UPDATE/START/EXIT events did,
and setpreason fired none of those.
2. backend/convert.go + convert_pure.go: cJobToModel / rawJobToModel now
extract xce_job_t.pend_reasons (main_reason + host/res reasons) and
marshal them into models.JobInfo.PendingReason as JSONB. models/jobs.go:
pending_reason added to JOB_DEFAULT_COLUMN so default job queries return
it (it was only in JSONBJFields, never selected).
Verified live on t1/t2/t3: a job with resreq "type == nosuchhost" stays
PEND and returns
"pending_reason":{"main_reason":0,"host_reasons":[{"host":"t1","reason":3},
{"host":"t2","reason":3},{"host":"t3","reason":3}]}
(main_reason=3 PREASON_MATCH_FAIL per host) via both /jobs list, /jobs/:id
and the SSE stream. 4 new unit tests (rawJobToModel pendReason marshal +
name mapping), all apiserver backend tests pass.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7b7294dd1e
commit
ac6131dbd7
6 changed files with 225 additions and 0 deletions
66
docs/aibot_poc_investiagting.md
Normal file
66
docs/aibot_poc_investiagting.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# AI Bot 对外 POC 能力建议(scheduler-agent MCP)
|
||||
|
||||
> 状态:建议稿(2026-08-13)。讨论稿,未实施。
|
||||
> 目标:对外 POC 演示 XCE 的 AI agent(scheduler-agent MCP)能力。出彩的关键不是"更多查询工具",而是**闭环 + 叙事**——让观众看到 agent 不只是读状态,还能诊断、能动手、能解释。
|
||||
|
||||
## 一、现状:已注册 14 个 MCP 工具
|
||||
|
||||
| 类别 | 工具 |
|
||||
|------|------|
|
||||
| 只读·状态(6) | `scheduler_list_jobs` / `get_job` / `list_queues` / `list_nodes` / `job_logs` / `cluster_metrics` |
|
||||
| 只读·高级(4) | `wait_job` / `analyze_failure` / `suggest_resources` / `estimate_wait_time` |
|
||||
| 写(4,需确认) | `submit`(dry_run 审查 + general_serial 模板)/ `cancel` / `hold` / `release` |
|
||||
|
||||
## 二、推荐增强方向(按 POC 性价比排序)
|
||||
|
||||
### 1. 失败作业「自愈闭环」— 首选,对外 POC 的 money shot
|
||||
现状 `analyze_failure` 只是"把数据打包给你看"。升级为 **诊断 → 归因 → 行动 → 复跑验证** 的闭环:
|
||||
- **归因分类**:按 exit code / signal / 日志特征分类——OOM、被信号杀(segfault/killed)、命令不存在、超时、基础设施失败(节点掉了);每类给一句人话解释 + 证据链
|
||||
- **自动重试策略**:OOM → 建议加内存重交;被信号杀 → 检查资源限值;脚本错误 → 不改资源、指出错在哪行
|
||||
- **自愈动作**:`rerunable` 作业 → 用调整后的规格 re-submit → `wait_job` 验证 → 报告"第一次 OOM 失败 → 加大内存后成功"
|
||||
|
||||
数据已齐(failinfo code、日志、submit 全参数);主要是把 `analyze_failure` + `submit` + `wait_job` 编排成智能逻辑。
|
||||
演示剧本:"提交一个会 OOM 的作业 → agent 自己把它修好跑通"。
|
||||
|
||||
### 2. 作业旅程「实时叙事」— 最便宜、最抓眼球
|
||||
SSE 事件流已建好(PEND→RUN→DONE),缺把事件转成有人味的实时解说:
|
||||
> "作业 #12 已排队(第 3 位)→ 预计 40s 后开始 → 已分配到 t2 节点(负载 30%)→ 运行中,耗时 2m10s → 完成 ✅"
|
||||
|
||||
配合 `wait_job` 即"提交后 agent 全程盯着并讲解"。live demo 连续跑几个作业画面感极强。工程量最小(prompt/模板活)。
|
||||
|
||||
### 3. 调度决策「解释」(PEND reason)— XCE 差异化,别家抄不走
|
||||
**"为什么我的作业等了 10 分钟 / 为什么没排到更空的节点?"** HPC 特有。
|
||||
scheduler 侧已有 PEND 原因(`PREASON_NO_RESOURCE`、`PREASON_MATCH_FAIL`、资源不满足 slots/mem…),agent 若能读取并翻译:
|
||||
> "作业 PEND 是因为 8 槽节点全满,你的 2 核需求需等 t3 释放 1 个作业(约 3 分钟)"
|
||||
|
||||
**前置检查(2026-08-13 完成)**:PEND reason 全链路**只差一环**——apiserver Go 转换层没填充 `PendingReason` 字段。详见下方「五、PEND reason 现状调查」。
|
||||
|
||||
### 4. 集群调优(数据可行,次优先级)
|
||||
- **热点/碎片化分析**:扫节点 + 资源分布 → "t1 长期 90% 满载、t3 只有 20%,建议放宽 big 队列 affinity"(`resources/distribution` + hosts 数据已可做)
|
||||
- **排空时间预测**:估算当前队列多久清空(`estimate_wait_time` 的队列维度扩展)
|
||||
- **配置变更 what-if**:模拟改队列限制/加节点对等待时间的影响——最"调优"但需调度模型,工程量最大,POC 后置
|
||||
|
||||
## 三、POC 演示剧本建议
|
||||
按感染力排序:**①自愈闭环(故事核心)→ ②实时叙事(视觉)→ ③PEND 解释(差异化)→ ④调优(收尾卖点)**。
|
||||
|
||||
## 四、待办
|
||||
- [x] 检查 PEND reason 全链路(scheduler → apiserver)是否暴露齐全(2026-08-13 完成,结论:只差 apiserver Go 转换层)
|
||||
- [ ] 补 apiserver 转换层:`cJobToModel` / `rawJobToModel` 填充 `PendingReason`(convert.go / convert_pure.go)
|
||||
- [ ] ① 自愈闭环:失败归因分类器 + 自愈复跑流程
|
||||
- [ ] ② 实时叙事 prompt/模板
|
||||
|
||||
## 五、PEND reason 现状调查(2026-08-13)
|
||||
|
||||
**结论:全链路只差一环——apiserver Go 转换层没把 C 的 `pend_reasons` 映射到 `models.JobInfo.PendingReason`,API 的 `pending_reason` 恒为空。** 上游全部就绪:
|
||||
|
||||
| 环节 | 状态 | 位置 |
|
||||
|------|------|------|
|
||||
| scheduler 计算并 publish PEND 原因 | ✅ | `sched_make_allocation` 返回 0 → `make_pend_decision(reason)`(scheduler.c:267);main.c:189 `sched_publish_pend_reason` → `setpreason` opcode |
|
||||
| 原因类型 | ✅ | `PREASON_BAD_RESREQ`/`NO_RESOURCE`/`MATCH_FAIL` + host/res 明细(preason.h;resource.c allocator `add_job_preason`) |
|
||||
| controller 存储 | ✅ | `do_set_preason` → `job->pend_reasons`(controller/job.c:2585-2613);`do_clr_preason` 清除 |
|
||||
| capnp wire 编解码 | ✅ | `JobInfo.pendreason @10` encode/decode(xce.build/lib/controller.capnp.c:6152/6168) |
|
||||
| C 结构体字段 | ✅ | `xce_job_t.pend_reasons`(src/include/xce/types.h:479) |
|
||||
| apiserver model | ✅ | `JobInfo.PendingReason json:"pending_reason"`(models/jobs.go:553)+ 在 `JSONBJFields`(:140),填充后 processJobData 会自动解析浮现(jobs.go:3208) |
|
||||
| **apiserver Go 转换** | ❌ | `cJobToModel`(backend/convert.go:74)与 `rawJobToModel`(backend/convert_pure.go:210)**均未读取 `pend_reasons`** → PendingReason 恒 nil |
|
||||
|
||||
**修复量**:小。在两个转换函数各加一段把 C `pend_reasons`(main_reason + host/res reasons)编码为 JSONB 塞进 `PendingReason`,配单测即可。
|
||||
Loading…
Add table
Add a link
Reference in a new issue