PR 一多就長時間排隊,發布工作又會把所有節點占滿。
最快解法:不要按開發者人數買 Mac Runner;按峰值任務到達量、任務時長、可接受排隊時間,再加上發布隔離與故障備援來計算。常規建置做基礎節點池,UI 測試與發布任務分流,短期峰值優先增加遠端 Mac,而不是全年按最高負載配置。

這篇文章適合三類人:

  • 正在維護 GitHub Actions 自託管 macOS Runner,卻無法判斷何時擴容的 DevOps 工程師。
  • 需要替多個 iOS 專案分配建置容量與發布窗口的移動研發負責人。
  • 準備租用遠端 Mac,希望先估算節點數量、租賃周期與試運行範圍的平台採購或工程負責人。
01

先確認:Runner 在線數量不等於有效並發

GitHub Actions 的任務會根據 Runner 的標籤與群組進行路由。自託管 Runner 只有在符合工作流要求、處於可接收任務狀態時,才可能被分配工作;單純看到節點在線,不代表它有可用容量。你可以先參考 GitHub 自託管 Runner 的路由規則,確認標籤、作業系統與架構條件。

估算前,從 GitHub Actions 指標與每次執行記錄整理以下欄位:

欄位 你要記錄的內容 用途
任務到達時間 PR、UI 測試、發布任務何時進入佇列 找出集中提交與發布峰值
排隊時間 從進入佇列到 Runner 開始執行的時間 判斷開發回饋是否已受影響
執行時長 從開始到成功或失敗的完整時間 估算單節點可消化的工作量
重試與失敗 失敗後重跑、超時、Runner 離線紀錄 避免把不穩定容量算進有效產能
任務類型 檢查、增量建置、UI 測試、歸檔、發布 決定哪些工作可以共享節點

GitHub 提供自託管 Runner 的監控與排障資料,但它不會替你的專案給出「應該配置幾台 Mac」的官方公式。容量模型必須使用你自己的工作流歷史校正,可從 官方監控與排障文件確認可觀察項目。

平均值很容易掩蓋問題。工作日的持續提交、版本發布前的集中歸檔,以及失敗重跑,都可能令短時間內的需求遠高於日均值。因此,基線至少要同時保留:

  • 一般工作日的持續負載。
  • 集中提交或回歸測試窗口。
  • 發布截止時間前的高峰負載。
  • 任務時長較長的高分位樣本,而非只有平均執行時間。

注意:不要把工作流並發、Runner 台數和單台 Mac 內的測試並行直接相加。這三者是不同層級的容量,重複計算會製造虛假的並發餘量。

02

PR 建置怎樣決定基礎節點池?

PR 場景的重點不是一次能跑多少任務,而是讓開發者在可接受時間內取得結果。程式碼檢查、單元測試和增量建置通常持續到達,適合先建立穩定的基礎節點池。

你可以把每一類任務分開計算:

  1. 以固定觀察窗口統計任務到達量。
  2. 取每類任務的典型執行時長,另記錄高峰時段的長任務。
  3. 設定可接受的排隊時間,而不是先指定 Runner 台數。
  4. 用窗口內的工作量推導初始並發,再以實際排隊結果回頭修正。
  5. 把取消、合併和移出後的任務重新計算,避免為無效工作購買容量。

例如,舊提交在新提交進入後仍繼續建置,會占用 Mac Runner,卻不再提供有用回饋。可利用 GitHub Actions 的 Concurrency 控制機制取消或限制同一分支上的過時工作。這一步應先於擴容,因為增加節點不能修復工作流本身的浪費。

同樣地,純粹的格式檢查、部分靜態分析或與 Apple 工具鏈無關的步驟,不一定需要放在 macOS Runner。先盤點哪些作業真正依賴 Xcode CI,再決定 Mac 節點池的大小。

第一個容量分支:先減少無效占用

  • 若舊提交可安全取消:在同一分支或同一變更範圍內設定併發控制,先減少重複建置。
  • 若多個檢查可以合併:合併工作流步驟,降低每個任務都啟動一次環境的固定成本。
  • 若步驟不依賴 macOS:移到其他既有執行環境,Mac Runner 只承擔必要工作。
  • 若優化後高峰排隊仍超過目標:才增加基礎節點,並以新的排隊資料驗證效果。
  • 若只有發布窗口受阻:不要擴大整個 PR 池,改設發布預留容量。

GitHub 的工作流語法可用於控制觸發條件、工作依賴和併發行為,具體寫法可查閱 官方 workflow syntax 文件

03

Simulator 與 UI 測試為何要另算?

UI 測試不只是「另一個建置工作」。一台 Mac 內可能同時承載編譯、Simulator、測試 Worker、測試結果寫入和清理工作。即使工作流表面上提高了並發,單機內部也可能因處理器、記憶體、磁碟 I/O 或模擬器爭用而變慢。

Apple 的 Xcode 建置計時說明可以協助你取得 Build Timing Summary,分辨編譯、連結及其他階段的時間;可參考 Apple 關於改善增量建置速度的文件。至於平行測試,則應以 Apple 的 Xcode 發布說明核對 xcodebuild 相關選項與行為,不要把網上經驗當作固定容量規則。

對每個 UI 測試工作流,至少觀察:

  • 增加測試 Worker 後,單次任務的有效完成時間是否縮短。
  • Simulator 啟動、重置和測試過程是否出現不穩定。
  • 建置與測試同時進行時,記憶體壓力及磁碟等待是否明顯增加。
  • 測試失敗是否集中發生在高並發窗口。
  • 失敗重跑後,整個佇列的完成時間是否反而延長。

容量處理可以遵循以下條件:

  • 若提高單機 Worker 後有效完成時間縮短且穩定:保留經驗證的單機並行度,再按工作流並發配置測試節點。
  • 若 Worker 增加後任務變慢或失敗率上升:限制單機並行,改用更多獨立測試節點。
  • 若 UI 測試與 PR 編譯互相阻塞:以標籤或 Runner Group 分流。
  • 若測試只在夜間執行:先使用時間窗口和佇列管理,不必把夜間峰值永久加入日常基礎池。

GitHub 支援以標籤及 Runner Group 將工作路由到指定節點;可參考 Runner 標籤與群組的路由方式。這比單純增加所有 Runner 的數量更容易維持測試隔離。

04

發布任務應否與普通建置共用?

簽名、歸檔和發布工作即使出現頻率較低,也不應只用平均負載判斷是否共用。發布 Runner 可能涉及鑰匙圈、憑證、暫存檔、工作區殘留和失敗後恢復。普通 PR 任務把節點占滿,可能不會影響日常測試,卻會直接阻斷交付窗口。

建議把發布節點視為受控容量:

  • 以標籤指定發布工作只能進入受控 Runner。
  • 以 Runner Group 限制可使用發布節點的儲存庫或工作流。
  • 每次環境變更後,完整跑一次歸檔任務,確認路由、等待和憑證可用性。
  • 把工作區清理、鑰匙圈狀態和失敗重試納入驗收,而不只看任務是否成功。
  • 保留發布窗口的專用或預留能力,避免普通任務把節點池填滿。

GitHub 的 Runner Group 管理說明可用來規劃這種權限及路由邊界。你也可以把發布節點與 PR 節點分開記錄,避免低頻發布工作被日常平均值掩蓋。

提醒:發布節點不一定要永久獨占一台實體 Mac。若能在發布前清空工作區、隔離憑證並驗證完整歸檔流程,才有條件與受控任務共享;否則,隔離本身就是容量成本。

05

夜間回歸和版本峰值怎樣安排?

日常負載、夜間回歸和版本發布前峰值應分開建模。可延後的工作,優先使用佇列與時間窗口;有明確截止時間的工作,才評估短期增加遠端 Mac。

負載類型 主要風險 優先處理方式 何時增加節點
PR 檢查與增量建置 回饋延遲,提交互相堆積 取消舊提交、移走非 macOS 步驟、建立基礎池 優化後高峰排隊仍超過目標
Simulator UI 測試 單機資源爭用、測試不穩 限制單機 Worker、獨立測試標籤 測試窗口無法在截止時間前完成
歸檔與發布 憑證污染、發布被普通任務阻塞 受控 Runner Group、預留容量 發布等待或恢復時間影響交付
夜間回歸 短時間工作量集中 排程、佇列、分批執行 排程後仍超過可用窗口
版本發布峰值 短期需求高,全年不持續 短周期擴容試跑 峰值在多個發布周期反覆出現

採購上有三種選擇:

  • 固定增加節點:適合 PR 負載穩定、每天都有容量需求的團隊。
  • 調整排程:適合夜間回歸可以延後,且沒有嚴格交付截止時間的專案。
  • 短周期增加遠端 Mac:適合版本發布前出現明確、可預測的短時峰值。

若你目前使用本地 Mac 或零散節點,先閱讀 KVMNODE 的遠端 Mac 節點方案,把租賃周期與發布窗口對照,而不是直接把高峰配置成全年固定成本。

06

用試運行把「幾台」變成可驗證結論

正式採購前,建議按工作流類型做小規模試運行。這不是追求一個漂亮的理論數字,而是找出排隊、資源爭用和故障恢復的實際邊界。

第一步:建立分組基線

把任務至少分成 PR 建置、Simulator UI 測試、發布歸檔和夜間回歸。每組記錄到達時間、等待時間、執行時間、失敗重跑及 Runner 狀態。不要把所有工作流混成一條平均線。

第二步:先驗證路由

用標籤和 Runner Group 確認 PR、測試及發布任務是否進入預期節點。觀察「節點在線但工作仍排隊」的情況,因為這可能是標籤不匹配、群組權限或節點正忙,而不一定代表台數不足。

第三步:逐步提高工作流並發

每次只改一項變數。先增加工作流並發,再觀察排隊時間、有效建置時間、失敗率和資源狀態。不要同時提高工作流並發及單機測試 Worker,否則無法判斷改善或退化的來源。

第四步:單獨驗證 UI 測試

在相同專案、相同測試集合下比較不同單機並行設定。若新增 Worker 只增加資源壓力,卻沒有縮短有效完成時間,應把容量轉移到更多獨立測試節點。

第五步:完整跑一次發布流程

使用正式工作流的歸檔、簽名、上傳及清理步驟,記錄等待時間與失敗恢復。發布容量不能只用 PR 成功率推算。

第六步:加入故障備用測試

模擬單一節點離線、重啟或工作區清理失敗,觀察任務是否能重新路由、等待多久,以及是否需要人工介入。備用容量的價值是維持交付,不是讓平日平均並發看起來更高。

最後用條件分支落地

觸發證據 容量決策 不應採取的做法
基礎池高峰排隊超標,且已完成工作流整理 增加 PR 基礎節點 只看在線數量就擴容
UI 測試提高單機並行後變慢或不穩 限制單機並行,增加獨立測試節點 把 Worker 數量當成等量新 Mac
發布曾被普通任務占滿 建立發布預留或專用路由 以日均發布次數判斷可共用
只有版本窗口出現短峰值 短期增加遠端 Mac 按全年最高峰永久配置
故障後無法在交付窗口內恢復 增加備用節點或明確故障轉移流程 把備用容量當作一般並發使用

若優化後的高峰排隊仍超過目標,選擇增加基礎節點;否則先維持現狀。
若只有 UI 測試受阻,選擇獨立測試池;否則不要把所有 PR Runner 一起擴大。
若發布窗口固定且失敗代價高,保留發布預留容量;若只是偶發峰值,先按周期租用。
若故障演練無法自動恢復,先補備援與清理流程,再談更多並發。

對需要跨地域配置的團隊,也可先比較 不同地區的遠端 Mac 交付選項,再以連線品質、工作流等待及管理方式決定試運行節點。

07

結論:先記錄一輪,再決定租幾台

一個 GitHub Actions Mac Runner 能否承擔你的任務,不應由開發者人數或供應商標稱配置決定。真正需要納入模型的是峰值到達量、任務時長、目標排隊時間、Simulator 內部爭用、發布隔離和故障備援。

如果你目前的方案是把所有工作混在少量本地 Mac 上,常見缺點是開發機被建置長時間占用、發布任務容易與 PR 互相阻塞,而且故障時缺少可快速替換的節點。若改用一般雲端 Linux 主機,又會遇到 macOS 專屬工具鏈、Xcode 及簽名流程無法直接承接的限制。對短期發布、夜間回歸或容量試算而言,租用 KVMNODE 的遠端 Mac,可以先按實測任務窗口增加節點,再決定是否保留長期容量;若你需要長期穩定重負載或實體介面,則應把自購 Mac 與專用硬體維護成本一併評估。

下一步不是猜一個台數。先用本文的負載表記錄一輪真實 PR、UI 測試和發布任務;若高峰容量確實不足,就按測得的窗口租用遠端 Mac 試跑,再用排隊時間、有效建置時間、失敗率和恢復結果決定長期方案。