fix(scheduler): select runners by capability (CI image availability + workspace-root reachability), and retry infrastructure failures elsewhere
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 5/5
- 预计耗时
- 一周以上
- 新手友好度
- 38/100
- Issue 类型
- 功能
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- docker, rust
调研方向
Start with crates/gitforge-scheduler/src/policy.rs and crates/gitforge-scheduler/src/assigner.rs to trace runner selection, then read crates/gitforge-sandbox/src/docker.rs for image availability behavior. Map how runner registration and heartbeats expose capabilities, and inspect existing scheduler contract tests. Done means tests cover image and workspace-root matching, explicit diagnostics when no runner qualifies, and retry history across different runners.
由索引模型根据 Issue 内容生成。
描述
Summary
The scheduler assigns CI jobs to a runner by declared capacity only. It has no model of what that runner can actually do for the job: which CI image it holds, and whether it can reach the job's workspace root. Both gaps produce deterministic, 100%-reproducible infrastructure_failure for any repository whose CI image or workspace is not available on the runner the scheduler happens to pick.
This is a design defect, not a transient.
Code evidence
crates/gitforge-scheduler/src/policy.rs:31-47—SimplePolicy::select_runnerfilters tostatus == "online" && capacity > 0and then takesmax_by_key(|r| r.capacity). The comment "In a real implementation, we'd track actual load" is still true of load; there is no capability term at all.crates/gitforge-scheduler/src/assigner.rs:394and:410— the production scheduler is constructed withSimplePolicy::new().crates/gitforge-scheduler/src/assigner.rs:1560—self.policy.select_runner(job_id, &available)is the whole selection step; the assignment carries the declared image but the selection never consults it.crates/gitforge-sandbox/src/docker.rs:361-425—ensure_imagefirst callsinspect_image; only if the image is not present locally does it pull. A bare reference such asdsc-ci-rust:14therefore resolves against Docker Hub, where the repository does not exist, and the job fails withfailed to pull image after 2 attempt(s): ... pull access denied for dsc-ci-rust, repository does not exist. There is no container registry in GitForge, and.gitforge.ymldocuments the intended contract: "The image must be pre-built on the host." Host-side presence is thus a hard precondition that the scheduler is blind to.
Measured impact
Read from the authoritative store (/var/lib/gitforge/gitforge.db, read-only) for jobs created since 2026-11-01. Totals: 1984 succeeded, 314 failed, 46 infrastructure_failure, 6 timed out, 26 skipped, 1604 cancelled.
The 46 infrastructure failures split into seven distinct classes:
| class | count | runners | window |
|---|---|---|---|
exec ... finished but its exit code could not be read / container lost before exec ... reported its exit code |
16 | swarmone-docker | 2026-11-01 to 2026-11-02 |
failed to pull image after 2 attempt(s) (404) |
11 | swarmone-docker 8, fedora-docker 3 | 2026-11-01 to 2026-11-04 |
workspace must be an existing absolute directory: /nas/Temp/repos/GitForge/workspaces/<run-id> |
11 | fedora-docker | 2026-11-03 21:24 to 22:10 |
failed to create workspace container: Timeout error |
4 | swarmone-docker | 2026-11-01 to 2026-11-03 |
acquisition timed out after 60 seconds |
2 | fedora-docker | 2026-11-04 |
step run failed at the container layer ... scratch free 0.0 GiB |
1 | swarmone-docker | 2026-11-01 |
error while creating mount source path ...: mkdir .../workspaces: file exists (sshfs) |
1 | fedora-docker | 2026-11-03 |
Representative job ids: b3b225ed-3ac3-426b-9b4d-0ea172402048 (pull 404), 63780150-8759-4e6e-ae29-3c17b0c86d59 (workspace not visible), 33cdd917-3bf4-4a76-adf2-e791ffbfa7e6 (exit code unreadable), a167040b-ae44-406f-8038-713fd4506b88 (mount source race), dd323d44-8065-4407-9063-a0389d5e4cdc (acquisition timeout).
Note the runner split: 29 of the 46 landed on swarmone-docker and 17 on fedora-docker. A single-cause account of "the fedora runner" does not fit this data.
Two capability gaps, proven separately
1. Image availability. The job declares image: dsc-ci-rust:14. On 2026-11-04 the fedora-docker runner did not hold that tag locally, and 3 of its jobs failed with the pull 404 above. The same tag was present on swarmone-docker, which the scheduler never chose for those runs because it declares capacity: 5 against swarmone-docker's 4. After copying the identical image (all 13 layer digests match) onto the Fedora runner, the next push-triggered run of the same repository was scheduled to fedora-docker and both jobs succeeded — pipeline run e3bd1f90-7e81-47ec-a3d7-33c3ae9f8fc9, commit 32dd2db860b8589a7daf6127756e4f35528946ac, job lint 931f378e-887e-4971-aba8-73e27deeb095 and job checks c5456fda-ccd8-4a2d-8e06-5c3291941dea, both exit code 0. The only variable changed was the runner's local image store, which is exactly the capability the scheduler should have selected on.
2. Workspace-root reachability. Push-run workspaces are materialized under /nas/Temp/repos/GitForge/workspaces/<run-id> on the SWARMONE host. The fedora-docker runner reaches that root over sshfs; a directory created seconds before dispatch is not yet visible to its bind-mount preflight, so the job fails before it starts with workspace must be an existing absolute directory. All 11 occurrences fall in a 45-minute window on 2026-11-03 (21:24 to 22:10). The adjacent mkdir ...: file exists failure on the same root is the same visibility problem seen from the other side.
Expected behavior
A runner should declare what it can execute, and the scheduler should match a job against declared capabilities rather than against free capacity alone.
- Runners report, at registration and on heartbeat: the CI images they hold locally, and the workspace roots they can serve (or a boolean per root).
- The assigner selects a runner whose capabilities satisfy the job's declared image and working-directory root; if none does, the job waits or is graded with an explicit, actionable diagnostic — not an opaque
infrastructure_failure. - An
infrastructure_failurethat is plausibly runner-local (image, workspace visibility, container create/acquisition timeout) is retried on a different eligible runner before the run is graded failed.
Acceptance criteria
- A contract test shows that a job whose declared image exists only on runner B is assigned to runner B, and that a runner without the image is not selected.
- A contract test shows that a runner which cannot reach the job's workspace root is not selected for that job.
- When no runner satisfies the job's capabilities, the run's terminal state names the unsatisfied capability (image / workspace root) instead of a generic sandbox error.
- An
infrastructure_failureis retried on a different eligible runner at least once, and the run's history records both attempts with their runners. - The runner-selection logic is unit-tested against the two-runner case where the higher-capacity runner lacks the image.
Notes
- The 46-job breakdown above was read from the store of record, not from a watcher. Job ids and run ids are included so the numbers can be re-derived.
- This issue does not claim that the seven classes above share one cause. Only classes 1 and 2 are scheduler-capability problems; the exit-code-unreadable and container-create-timeout classes are runner-local execution faults that the retry behavior in the third bullet would also absorb.
- 主要语言
- Rust
- 星标
- 1
- 派生
- 0
- 平均合并
- 1 天 7 小时
- 30 天内合并 PR
- 32
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
aliasfoxkde/GitForge 的其他 Issue
-
enhancement
难度 5/5 一周以上 新手友好度 15/100
aliasfoxkde/GitForge#371 ·
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 18/100
aliasfoxkde/GitForge#364 ·
维护者通常 1 天内回复
-
security(high): webhook trigger endpoint has no repo-ownership check (any user can run any pipeline)未关闭
难度 3/5 半天 新手友好度 42/100
aliasfoxkde/GitForge#358 ·
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 25/100
aliasfoxkde/GitForge#357 ·
维护者通常 1 天内回复
-
难度 5/5 一周以上 新手友好度 25/100
aliasfoxkde/GitForge#342 · 1 条评论 ·
维护者通常 1 天内回复
查看 aliasfoxkde/GitForge 的全部 Issue
相似的 Issue
-
agent-self
难度 2/5 1-3 小时 新手友好度 84/100
yologdev/yoyo-evolve#1176 ·
-
难度 2/5 1-3 小时 新手友好度 67/100
Richard-Zhang1019/Crossbow#431 ·
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 86/100
saschanaz/jxl-winthumb#69 ·
-
ready
难度 1/5 1 小时以内 新手友好度 88/100
TusanHomichi/PSIV#504 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 75/100
维护者通常 1 天内回复