VPSSpark 博客
← 返回开发日记

为什么 GitHub Actions macOS Job 一直卡在 Queued(不是 Xcode 慢)

机房手记 · Cloud Mac CI #2 · 2026.06.05 · 约 14 分钟阅读

常见搜索:GitHub Actions macOS 一直排队 · macOS runner 卡在 Queued · CI 排队时间过长 · 自托管 runner 不启动 · macOS 构建队列拥堵 (macOS runner queued · stuck in queued · CI queue wait time high · self-hosted runner not starting)

GitHub Actions macOS runner queue 界面显示 Job 处于 Queued 状态
macOS runner queued 时,先量 wait time,再谈 run time。

VPSSpark CI Queue Diagnosis Standard(Cloud Mac CI 系列 #2)。下文阅读顺序:Hook → 主公式 → 症状 → Failure Model → Hard Rules → Runbook → FAQ。延伸:#1 容量 · #3 自托管算账 · #5 扩员 · #8 构建提速。

1 · Hook:反直觉结论

99% 的 macOS CI queued 问题,不是资源不足,而是 L2(Archive)被错误放进 PR 路径。

2 · 核心:唯一主公式

全文只认下面这一条。其余章节都是它的展开。

主公式

CI queue problem  ⇔  wait time  >>  run time

工程结论: macOS runner queued = Runner pool 饱和,而不是 build 变慢。

若公式不成立 → 非本篇,转系列 #8(Xcode / Cache)。若成立 → 对号入座 Failure 3 Layer Model,并落实 CI Hard Rules

3 · 症状:Queued ≠ Running

GitHub Actions 里,Queued 表示 Job 已进 workflow,但还没拿到 Runner 槽位In progress 之后才是 checkout、xcodebuild、签名。很多 iOS 团队把「PR 红了 1 小时」当成编译慢——打开时间轴才发现:52 分钟在等,真正 run 只有 11 分钟

这类误判的代价是买错药:升级 Xcode、加 timeout-minutes、加 GitHub 分钟包——Queued 时间往往不计入你以为的构建超时,团队只是在日历上多等一天。

Queued = Job 已进 workflow,尚未拿到 Runner 槽位In progress 后才是 xcodebuild。实录:wait 52 min · run 11 min——团队误以为是 Xcode 慢。度量见 Job 执行时间queue_wait_seconds vs run duration)。

52 min
wait time
11 min
run time
Queued
≠ In progress
wait time run time
界面 Queued In progress
瓶颈 GitHub Actions macOS runner queue / self-hosted runner queue Xcode · 签名 · 上传
误操作 加 minutes · 换 Xcode 加缓存(→ #8)

4 · 解释:CI Queue Failure 3 Layer Model

wait time >> run time 成立,主因落在下面三层之一(SRE 命名,便于写 incident runbook)。

Layer 含义 典型信号 当天动作
Capacity Limit 平台 · macos-latest 仅托管 macOS runner queued;minutes ≠ concurrency 减 fanout;Archive 迁出托管 → #3
Pool Misdesign 架构 · self-hosted pool Archive 进 PR;fast/archive 未分离;单机 busy 全线 Queued 落实 Hard Rules → #1 #6
Trigger Explosion 负载 · workflow fanout matrix / paths / 重复 workflow;Job 数 > Runner 数 收紧触发器 → #5

Capacity Limit托管 macOS RunnermacOS concurrency caplimits)。Pool Misdesign — 多数案例主因:Job tier L2 误入 PR、fast/archive 混池。Trigger Explosion — 修法在 YAML,不在加机器。(注:Failure Layer 与下文 Job 层级 L0/L1/L2 是两套命名。)

5 · 解决:CI Hard Rules(MUST NOT violate)

工程规范语言。三条规则不可协商。

CI Hard Rules
Rule 1: PR MUST NOT run L2
                Rule 2: L2 MUST run on isolated pool  (macos-archive)
                Rule 3: fast pool MUST remain unblocked  (fast ≠ archive)

                # 落实映射
                PR     → L0 + L1 only     → macos-fast
                main   → L2 only            → macos-archive

L0 / L1 / L2 类型参考(服务于 Hard Rules,非第二套模型):

层级 内容 与铁律
L0 单模块编译、静态检查、轻量单测 macos-fast Rule 1 · PR 可跑
L1 PR 集成、模拟器测试 macos-fast Rule 1 · MUST NOT Archive
L2 Archive、IPA、TestFlight macos-archive Rule 2 + 3 · PR MUST NOT

图 1 · Pool Misdesign(L2):占槽 → 全线 macOS runner queued

PR 触发 6 个 macOS Jobmatrix 未收敛
L2 Archive 占满 Runner 38 min
L0/L1 全部 Queuedself-hosted runner queue 堵塞
workflow 规则示例(PR 不进 L2)
jobs:
                  pr-fast:
                    if: github.event_name == 'pull_request'
                    runs-on: [self-hosted, macos-fast]
                    # L0 + L1 only

                  release-archive:
                    if: github.ref == 'refs/heads/main' || github.event_name == 'schedule'
                    runs-on: [self-hosted, macos-archive]
                    # L2 only · dedicated pool

Runner 拓扑延伸:弹性池 vs 常驻 · #1 容量 · queue 止血后加机器 → #3

6 · Runbook:一页纸(可转发 on-call)

CI Queue Diagnosis · Standard Path
0. CI queue problem ⇔ wait time >> run time  ?  ─No→ #8
                1. Failure layer: Capacity | Pool Misdesign | Trigger Explosion
                2. MUST: Rule1 PR no L2 · Rule2 L2 isolated · Rule3 fast unblocked
                3. PR workflow 无 archive/export/upload ?
                4. wait P95 < 8min → 再评估 Runner (#3)

一句话结论: 99% 的 macOS CI queued 问题,不是资源不足,而是 L2 被错误放进 PR 路径。 macOS runner queued = Runner pool 饱和信号;先 wait >> run,再 Failure Model,再 Hard Rules。

7 · FAQ

为什么 macOS runner 更容易出现 queued?

Capacity Limit(macOS concurrency cap)+ Pool Misdesign(L2 进 PR)。先 wait >> run,再 Failure 3 Layer

怎么一眼判断是 queue 还是 build 问题?

唯一主公式:CI queue problem ⇔ wait time >> run time。成立 → Runner pool;不成立 → #8。

self-hosted runner 为什么也会 queued?

Pool Misdesignself-hosted runner queue 由池设计决定。违反 Hard Rules(L2 进 PR、fast/archive 混池)即堵——与是否 Cloud Mac 无关。

GitHub Actions minutes 和 concurrency 有什么区别?

minutes = 计费;concurrency = 占槽。加 minutes 不解决 macOS runner queuedCapacity Limit 层)。

怎么判断是不是 runner pool 问题?

wait >> run + 自托管单机 long busy → Pool Misdesign;仅 macos-latest queued → Capacity Limit。见 Runbook

queue 正常了但 build 仍慢,读哪篇?

系列 #8(构建提速)。问买几台:系列 #1。问扩员后为何崩:系列 #5。

系列导航(#2 排队诊断)
#1 容量 · #2 本篇 · #3 自托管算账 · #4 Xcode Cloud · #5 20 人案例 · #6 Archive 独占 · #7 平台选型 · #8 提速

验证分池:需要一台「快池」试跑时

Hard Rules 落实后,若要把 L0/L1 迁出托管 GitHub Actions macOS runner queue,可用 1 台 macos-fast Runner 做 PoC——验证 wait time P95 < 8 min,再按 #1macos-archive

若你希望按天拉起一台隔离快池、不改办公室网络,可在 Mac 云主机方案VPSSpark 首页 开通 Cloud Mac 做分池验证——这是拓扑验证手段,不能替代 workflow 规则。系列 #3 将专门算 self-hosted 是否值得。

限时特惠

macOS runner queued?先量 queue wait time

GitHub Actions macOS runner queue · CI 排队诊断

返回首页
限时优惠 点击查看套餐