PR 一多就長時間排隊,發布工作又會把所有節點占滿。
最快解法:不要按開發者人數買 Mac Runner;按峰值任務到達量、任務時長、可接受排隊時間,再加上發布隔離與故障備援來計算。常規建置做基礎節點池,UI 測試與發布任務分流,短期峰值優先增加遠端 Mac,而不是全年按最高負載配置。
這篇文章適合三類人:
- 正在維護 GitHub Actions 自託管 macOS Runner,卻無法判斷何時擴容的 DevOps 工程師。
- 需要替多個 iOS 專案分配建置容量與發布窗口的移動研發負責人。
- 準備租用遠端 Mac,希望先估算節點數量、租賃周期與試運行範圍的平台採購或工程負責人。
先確認:Runner 在線數量不等於有效並發
GitHub Actions 的任務會根據 Runner 的標籤與群組進行路由。自託管 Runner 只有在符合工作流要求、處於可接收任務狀態時,才可能被分配工作;單純看到節點在線,不代表它有可用容量。你可以先參考 GitHub 自託管 Runner 的路由規則,確認標籤、作業系統與架構條件。
估算前,從 GitHub Actions 指標與每次執行記錄整理以下欄位:
| 欄位 | 你要記錄的內容 | 用途 |
|---|---|---|
| 任務到達時間 | PR、UI 測試、發布任務何時進入佇列 | 找出集中提交與發布峰值 |
| 排隊時間 | 從進入佇列到 Runner 開始執行的時間 | 判斷開發回饋是否已受影響 |
| 執行時長 | 從開始到成功或失敗的完整時間 | 估算單節點可消化的工作量 |
| 重試與失敗 | 失敗後重跑、超時、Runner 離線紀錄 | 避免把不穩定容量算進有效產能 |
| 任務類型 | 檢查、增量建置、UI 測試、歸檔、發布 | 決定哪些工作可以共享節點 |
GitHub 提供自託管 Runner 的監控與排障資料,但它不會替你的專案給出「應該配置幾台 Mac」的官方公式。容量模型必須使用你自己的工作流歷史校正,可從 官方監控與排障文件確認可觀察項目。
平均值很容易掩蓋問題。工作日的持續提交、版本發布前的集中歸檔,以及失敗重跑,都可能令短時間內的需求遠高於日均值。因此,基線至少要同時保留:
- 一般工作日的持續負載。
- 集中提交或回歸測試窗口。
- 發布截止時間前的高峰負載。
- 任務時長較長的高分位樣本,而非只有平均執行時間。
注意:不要把工作流並發、Runner 台數和單台 Mac 內的測試並行直接相加。這三者是不同層級的容量,重複計算會製造虛假的並發餘量。
PR 建置怎樣決定基礎節點池?
PR 場景的重點不是一次能跑多少任務,而是讓開發者在可接受時間內取得結果。程式碼檢查、單元測試和增量建置通常持續到達,適合先建立穩定的基礎節點池。
你可以把每一類任務分開計算:
- 以固定觀察窗口統計任務到達量。
- 取每類任務的典型執行時長,另記錄高峰時段的長任務。
- 設定可接受的排隊時間,而不是先指定 Runner 台數。
- 用窗口內的工作量推導初始並發,再以實際排隊結果回頭修正。
- 把取消、合併和移出後的任務重新計算,避免為無效工作購買容量。
例如,舊提交在新提交進入後仍繼續建置,會占用 Mac Runner,卻不再提供有用回饋。可利用 GitHub Actions 的 Concurrency 控制機制取消或限制同一分支上的過時工作。這一步應先於擴容,因為增加節點不能修復工作流本身的浪費。
同樣地,純粹的格式檢查、部分靜態分析或與 Apple 工具鏈無關的步驟,不一定需要放在 macOS Runner。先盤點哪些作業真正依賴 Xcode CI,再決定 Mac 節點池的大小。
第一個容量分支:先減少無效占用
- 若舊提交可安全取消:在同一分支或同一變更範圍內設定併發控制,先減少重複建置。
- 若多個檢查可以合併:合併工作流步驟,降低每個任務都啟動一次環境的固定成本。
- 若步驟不依賴 macOS:移到其他既有執行環境,Mac Runner 只承擔必要工作。
- 若優化後高峰排隊仍超過目標:才增加基礎節點,並以新的排隊資料驗證效果。
- 若只有發布窗口受阻:不要擴大整個 PR 池,改設發布預留容量。
GitHub 的工作流語法可用於控制觸發條件、工作依賴和併發行為,具體寫法可查閱 官方 workflow syntax 文件。
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 的數量更容易維持測試隔離。
發布任務應否與普通建置共用?
簽名、歸檔和發布工作即使出現頻率較低,也不應只用平均負載判斷是否共用。發布 Runner 可能涉及鑰匙圈、憑證、暫存檔、工作區殘留和失敗後恢復。普通 PR 任務把節點占滿,可能不會影響日常測試,卻會直接阻斷交付窗口。
建議把發布節點視為受控容量:
- 以標籤指定發布工作只能進入受控 Runner。
- 以 Runner Group 限制可使用發布節點的儲存庫或工作流。
- 每次環境變更後,完整跑一次歸檔任務,確認路由、等待和憑證可用性。
- 把工作區清理、鑰匙圈狀態和失敗重試納入驗收,而不只看任務是否成功。
- 保留發布窗口的專用或預留能力,避免普通任務把節點池填滿。
GitHub 的 Runner Group 管理說明可用來規劃這種權限及路由邊界。你也可以把發布節點與 PR 節點分開記錄,避免低頻發布工作被日常平均值掩蓋。
提醒:發布節點不一定要永久獨占一台實體 Mac。若能在發布前清空工作區、隔離憑證並驗證完整歸檔流程,才有條件與受控任務共享;否則,隔離本身就是容量成本。
夜間回歸和版本峰值怎樣安排?
日常負載、夜間回歸和版本發布前峰值應分開建模。可延後的工作,優先使用佇列與時間窗口;有明確截止時間的工作,才評估短期增加遠端 Mac。
| 負載類型 | 主要風險 | 優先處理方式 | 何時增加節點 |
|---|---|---|---|
| PR 檢查與增量建置 | 回饋延遲,提交互相堆積 | 取消舊提交、移走非 macOS 步驟、建立基礎池 | 優化後高峰排隊仍超過目標 |
| Simulator UI 測試 | 單機資源爭用、測試不穩 | 限制單機 Worker、獨立測試標籤 | 測試窗口無法在截止時間前完成 |
| 歸檔與發布 | 憑證污染、發布被普通任務阻塞 | 受控 Runner Group、預留容量 | 發布等待或恢復時間影響交付 |
| 夜間回歸 | 短時間工作量集中 | 排程、佇列、分批執行 | 排程後仍超過可用窗口 |
| 版本發布峰值 | 短期需求高,全年不持續 | 短周期擴容試跑 | 峰值在多個發布周期反覆出現 |
採購上有三種選擇:
- 固定增加節點:適合 PR 負載穩定、每天都有容量需求的團隊。
- 調整排程:適合夜間回歸可以延後,且沒有嚴格交付截止時間的專案。
- 短周期增加遠端 Mac:適合版本發布前出現明確、可預測的短時峰值。
若你目前使用本地 Mac 或零散節點,先閱讀 KVMNODE 的遠端 Mac 節點方案,把租賃周期與發布窗口對照,而不是直接把高峰配置成全年固定成本。
用試運行把「幾台」變成可驗證結論
正式採購前,建議按工作流類型做小規模試運行。這不是追求一個漂亮的理論數字,而是找出排隊、資源爭用和故障恢復的實際邊界。
第一步:建立分組基線
把任務至少分成 PR 建置、Simulator UI 測試、發布歸檔和夜間回歸。每組記錄到達時間、等待時間、執行時間、失敗重跑及 Runner 狀態。不要把所有工作流混成一條平均線。
第二步:先驗證路由
用標籤和 Runner Group 確認 PR、測試及發布任務是否進入預期節點。觀察「節點在線但工作仍排隊」的情況,因為這可能是標籤不匹配、群組權限或節點正忙,而不一定代表台數不足。
第三步:逐步提高工作流並發
每次只改一項變數。先增加工作流並發,再觀察排隊時間、有效建置時間、失敗率和資源狀態。不要同時提高工作流並發及單機測試 Worker,否則無法判斷改善或退化的來源。
第四步:單獨驗證 UI 測試
在相同專案、相同測試集合下比較不同單機並行設定。若新增 Worker 只增加資源壓力,卻沒有縮短有效完成時間,應把容量轉移到更多獨立測試節點。
第五步:完整跑一次發布流程
使用正式工作流的歸檔、簽名、上傳及清理步驟,記錄等待時間與失敗恢復。發布容量不能只用 PR 成功率推算。
第六步:加入故障備用測試
模擬單一節點離線、重啟或工作區清理失敗,觀察任務是否能重新路由、等待多久,以及是否需要人工介入。備用容量的價值是維持交付,不是讓平日平均並發看起來更高。
最後用條件分支落地
| 觸發證據 | 容量決策 | 不應採取的做法 |
|---|---|---|
| 基礎池高峰排隊超標,且已完成工作流整理 | 增加 PR 基礎節點 | 只看在線數量就擴容 |
| UI 測試提高單機並行後變慢或不穩 | 限制單機並行,增加獨立測試節點 | 把 Worker 數量當成等量新 Mac |
| 發布曾被普通任務占滿 | 建立發布預留或專用路由 | 以日均發布次數判斷可共用 |
| 只有版本窗口出現短峰值 | 短期增加遠端 Mac | 按全年最高峰永久配置 |
| 故障後無法在交付窗口內恢復 | 增加備用節點或明確故障轉移流程 | 把備用容量當作一般並發使用 |
若優化後的高峰排隊仍超過目標,選擇增加基礎節點;否則先維持現狀。
若只有 UI 測試受阻,選擇獨立測試池;否則不要把所有 PR Runner 一起擴大。
若發布窗口固定且失敗代價高,保留發布預留容量;若只是偶發峰值,先按周期租用。
若故障演練無法自動恢復,先補備援與清理流程,再談更多並發。
對需要跨地域配置的團隊,也可先比較 不同地區的遠端 Mac 交付選項,再以連線品質、工作流等待及管理方式決定試運行節點。
結論:先記錄一輪,再決定租幾台
一個 GitHub Actions Mac Runner 能否承擔你的任務,不應由開發者人數或供應商標稱配置決定。真正需要納入模型的是峰值到達量、任務時長、目標排隊時間、Simulator 內部爭用、發布隔離和故障備援。
如果你目前的方案是把所有工作混在少量本地 Mac 上,常見缺點是開發機被建置長時間占用、發布任務容易與 PR 互相阻塞,而且故障時缺少可快速替換的節點。若改用一般雲端 Linux 主機,又會遇到 macOS 專屬工具鏈、Xcode 及簽名流程無法直接承接的限制。對短期發布、夜間回歸或容量試算而言,租用 KVMNODE 的遠端 Mac,可以先按實測任務窗口增加節點,再決定是否保留長期容量;若你需要長期穩定重負載或實體介面,則應把自購 Mac 與專用硬體維護成本一併評估。
下一步不是猜一個台數。先用本文的負載表記錄一輪真實 PR、UI 測試和發布任務;若高峰容量確實不足,就按測得的窗口租用遠端 Mac 試跑,再用排隊時間、有效建置時間、失敗率和恢復結果決定長期方案。