双队列思维 · 标签路由 · concurrency · 合并车道可验收
在多台租用的远程 Mac 上挂自托管 Runner时,最常栽在「以为 Merge Queue 会替你排机器队」:GitHub 侧的合并队列管的是变更进入默认分支的顺序与安全闸,Runner 侧的 backlog 仍然由标签与并发组决定。本文用控制面分工表拆开两台「队列」,给出ci-pr / ci-merge / ci-release标签路由、concurrency 与cancel-in-progress的勾选规则、以及p95 排队先改拓扑还是先拧 GitHub 旋钮的判据;并与共享构建池、并发席位锁、Mac Mesh 任务调度互链。
Merge Queue 解决的是主干完整性:把多部并入默认分支的检查编排成可序列推进的批次;它不替你保证远程 Mac Runner 上永远有空闲 CPU。若 PR 检查与 merge 检查共用同一组runs-on标签,会出现「GitHub 认为可以推进合并,但 Runner 正在跑十条可选检查」的错位。
双队列误读:把 Actions 列表里的「Queued」误以为 Merge Queue 会自动抬高 merge 作业优先级。
标签混用:ci 一类笼统标签把 nightly、PR、merge 压在同一 Runner 上。
错误取消:在 merge lane 上启用与 PR 相同的cancel-in-progress: true,批次中途被反复冲掉。
并发组名碰撞:多仓或多 workflow 共用同一concurrency字符串,互相误杀。
观测缺失:没有区分「merge queue 等待时间」与「Runner 忙时占比」,扩容谈判缺少数据。
与 mesh 锁冲突:合并车道需要稳定占用节点时,未与切节点租约对齐。
提示:若你仍在比较本机与远端分工而非 CI 控制面,请先读本机轻编辑与远端重编译 thresholds 文。
以下对照表用于评审会白板;「两者兼顾」通常是默认起步点,前提是 Runner 容量诚实,而不是标签自欺。
| 控制面 | GitHub Merge Queue | Runner backlog(机器队列) |
|---|---|---|
| 管什么 | 进入默认分支的顺序、合并批次、required checks 语义 | 哪台 Mac 什么时候执行哪条 workflow job |
| 不管什么 | 你的 M4 有几个空闲性能核 | PR 是否「逻辑上该插队」 |
| 典型失败 | 批次反复超时(逻辑正确但算力不足) | merge job 长期 Queued 而 queue 很短 |
| 缓解第一刀 | 收紧 required checks、拆分批次假设 | 拆分runs-on标签、加 Runner 或专席 Reserve |
合并是否「丝滑」取决于 Runner 是否给 merge 留了名字诚实的容量,而不是 Merge Queue 开关本身。
self-hosted + macOS + ci-pr + 工具链版本(如 xcode-16-2)。ci-merge,由至少一台远程 Mac Runner 承接。ci-release,与 merge 分开,避免发版巨型任务饿死 trunk。下列步骤可与共享池 SSH 编排文并行:旧文解决「能否连上 Runner」,本文解决「谁有权占用哪条 CPU 时间线」。
盘点 required checks:把默认分支真正阻塞合并的检查列成表,标注预计时长与是否可在 PR 阶段前置。
拆分 runs-on:为 merge 专用 workflow 或 job 配上 ci-merge 标签,物理上可由同一台机器注册多标签,但必须能预留时间段或使用独立节点。
检查 concurrency:PR workflow 使用cancel-in-progress: true减少过时提交排队;merge/release lane 使用cancel-in-progress: false或更窄的分组键。
命名 concurrency 组:包含 repo、workflow 名与环境后缀,避免组织内撞车。
埋点:至少在团队看板区分 GitHub「merge queue 等待」与 Runner「busy minutes」两类序列。
门禁复盘:若一周出现两次以上「queue 短但 merge job 长 Queued」,优先改 Runner 拓扑再讨论 GitHub 并行度。
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
merge-gate:
runs-on: [self-hosted, macOS, ci-merge, xcode-16-2]
timeout-minutes: 45
steps:
- run: echo "merge lane only"
下列信号来自常见工程复盘口径,请用自有数据替换阈值;关键是不要把两类等待混在同一页图上。
| 现象 | 更可能根因 | 第一动作 |
|---|---|---|
| merge queue 很长,Runner 很闲 | required checks 或批次策略过严 | 审查 checks 图与并行假设 |
| queue 很短,merge job 长期 Queued | 标签路由或 Runner 数不足 | 拆 ci-merge、加节点或专席 |
| 批次频繁失败「基础设施」 | 超时、磁盘、钥匙串或网络抖动 | 对照 Runner 日志与签名治理清单 |
| PR 很快 merge 很慢 | PR 与 merge 争用同一标签 | 拆分 runs-on 并收紧 PR optional jobs |
注意:给 merge 加「更快机器」而不拆标签,往往只是把饥饿推迟到发布夜;长期仍需独立容量名。
下列区间为多国团队常见立项核对经验值;请把采集 SQL 或 API 字段写进内部 runbook。
ci-merge同名 Runner 时,busy 分钟占比若在工作时段高于 85%,应拆 nightly 到ci-pr池。concurrency是否与 PR 共用同一分组策略。| 团队规模 | 主干合并频率 | 推荐第一招 |
|---|---|---|
| 小团队 | 每日多次 | 一台专用 ci-merge Runner + 严格 required checks |
| 中型团队 | 持续有批次 | 多区域 Runner + 明确定义的 release 池 |
| 平台化 | 多仓共用池 | 组织级标签规范 + 成本看板拆分 queue vs runner |
把笔记本当「临时 Runner」会引入休眠、温控与不可审计交互登录;自建机房 Mac 则要扛采购与多地布线。两者都难以把合并 SLO写进可复盘合同。
对需要iOS CI/CD 与 AI Agent 长任务共存的远程 Mac 池,VpsMesh 的 Mac Mini 云端租赁通常是更优解:可按区域与规格扩展 Runner Fleet,把 merge、release 与日常杂活拆到可命名节点上,并把可用性与席位策略落到运维条款,而不是群聊默契。