GitHub 的 workflow_job 事件會把 Job 分成 queued、in_progress、completed 三種狀態,這正好提供容量估算所需的時間邊界:官方 Webhook 事件文件 可作為記錄依據。由此推出本週建議:不要按開發者人數計算 Mac 數量,而要按峰值並發 Job、每個 Job 的主機占用時間、可接受排隊時間與發布隔離要求決定。低頻單人專案先用單機;建置、測試與發布反覆重疊時改用雙機或按需擴容;多人多 App 團隊則用真實隊列資料滾動調整。

這篇文章適合三類讀者:已配置 GitHub Actions self-hosted runner,但不確定一台遠端 Mac 是否足夠的獨立開發者;需要讓 Pull Request 測試與 TestFlight 發布並行的小團隊;以及只在發版波峰需要額外主機、希望按週或按月租用而非購買閒置硬體的項目負責人。

01

先分清 Job、Runner 與 Mac:不要把工作流次數當容量

GitHub Actions 的 Workflow 是流程定義,Job 是可排隊與執行的工作單位,Runner 是接收 Job 的執行環境,而 Mac 才是承載 Runner 的實體主機。Xcode 內部的編譯並行,也不等於 GitHub Actions 層面的多個 Job 並行。

這個區分會直接影響結論:

  • 同一個 Workflow 可能包含建置、測試、Archive 及上傳等不同 Job。
  • App Store Connect 的後台處理,不應整段算成 Runner 一直占用。
  • Job 進入 completed 後,主機可能已經釋放,但遠端服務仍在處理上傳結果。
  • 一台 Mac 的 CPU、記憶體、硬碟空間、模擬器狀態和簽名環境,仍可能成為實際瓶頸。
  • Runner 標籤只負責路由,不能保證某個 Job 一定有足夠資源;標籤配置可參考 GitHub 的 Runner 標籤說明

因此,先把每個 Job 拆成四段記錄:

  1. 等待 Runner 的時間。
  2. Runner 已接手但仍在執行的時間。
  3. 需要 Mac 資源的步驟,例如 xcodebuild、模擬器測試與 Archive。
  4. 不再占用 Runner 的服務端等待,例如上傳後的處理。

容量計算只應把第二、第三段納入主機占用。若把所有等待都算進去,會高估 Mac 數量;若只看每日總建置次數,又會漏掉發布窗口的瞬間重疊。

02

單人低頻與單人高頻:先分流,再決定一台或兩台

低頻獨立開發者:單機起步,但要設優先級

單人維護一個 App,提交頻率不高、測試矩陣有限,且正式 Archive 可以錯峰時,單台 Mac 通常是合理起點。這不是因為單機一定更快,而是目前沒有足夠的重疊負載證明需要第二台。

建議將工作流分成三個優先級:

  • 一般提交驗證:保留編譯、靜態檢查及必要測試。
  • 定時測試:安排在不影響緊急修復的時段。
  • 正式 Archive 與上傳:使用獨立標籤或至少獨立的觸發條件。

如果單機經常排隊,先排除三種假性容量不足:

  • 每個 Job 重複下載依賴,實際上是快取沒有設計好。
  • 同一提交被多次觸發,沒有取消過時工作流。
  • 測試矩陣過大,包含並不影響當前決策的重複組合。

GitHub 提供工作流並發控制,可以取消不再有價值的舊執行:官方並發控制文件。完成這項整理後仍在關鍵窗口排隊,才進入雙機評估。

高頻獨立開發者:第二台 Mac 的價值是並行與回退

如果同時維護多個功能分支、頻繁產出 TestFlight 建置,單機平均利用率可能不高,但發版時仍會持續排隊。這是最容易誤判的情況:平均值看似足夠,峰值卻讓發布被一般測試卡住。

此時比較三個動作:

  • 先拆 Workflow:把 Pull Request 驗證和發布流程分開,避免一個流程的失敗阻塞另一個流程。
  • 取消過時 Job:新提交出現時,取消仍未開始的舊驗證。
  • 增加第二個 Runner 環境:讓測試與 Archive 可以同時執行,也保留一台主機維護時的回退路徑。

第二台 Mac 不會自動提升單一 Job 的速度。它解決的是兩個 Job 不能同時占用同一環境的問題,也降低發布時沒有可用 Runner 的風險。若瓶頸是單次編譯、依賴下載或測試本身太慢,應先用 Xcode 的計時資料定位;Apple 的 Xcode 建置計時文件 可用來檢查增量建置步驟。

03

小團隊與多 App:用反饋時限和安全邊界分層

小團隊:不追求零排隊,而是守住可接受等待

多人提交 Pull Request 時,容量標準不應是 Runner 永不排隊,而是程式碼反饋是否能在團隊接受的時間內返回。請把 Job 分成:

  • 快速檢查:編譯、Lint、單元測試。
  • 模擬器測試:占用較多 Mac 資源,可能與其他測試競爭。
  • 生產發布:涉及 Archive、簽名、上傳及更高的憑證保護要求。

普通任務不要路由到生產發布 Runner。用標籤或 Runner Group 分離環境,並限制哪些工作流可以使用發布標籤。GitHub 對 Job 的 Runner 選擇與標籤路由有明確說明,可參考 Runner 選擇規則

小團隊的雙機方案至少要通過三項驗證:

  • 普通測試進入測試 Runner,發布 Job 不會被錯誤路由。
  • 某台 Mac 重啟或維護時,仍有可用的發布路徑。
  • 簽名憑證、Provisioning Profile、Bundle ID 與 Team ID 沒有在不必要的 Runner 間擴散。

多 App 或固定發版團隊:常駐容量與臨時容量分開

多個 Repository 共用 Mac 時,應按 Repository、Job 類型和安全等級分層,而不是讓所有工作流爭搶同一個標籤。

可以比較以下三種配置:

  • 常駐基礎容量:保留一台或一組 Runner 處理日常驗證,適合每天都有穩定提交的團隊。
  • 發版期臨時擴容:只有測試高峰或發布窗口才增加遠端 Mac,適合平時閒置、波峰明顯的團隊。
  • 完全獨立發布機:生產 Archive 和簽名始終使用獨立 Mac,適合憑證隔離與回退要求高的團隊。

停止條件也要先寫好。當發布窗口結束、佇列恢復到可接受範圍,而且新增環境已完成產物與憑證清理,就可以停止臨時容量。若每次擴容都需要重新安裝 Xcode、匯入憑證和手動修復 Runner,彈性方案的交付速度可能抵銷它的成本優勢。

04

FAQ:五個容量判斷場景

一台自託管 Mac 可以同時處理多個 iOS Job 嗎?

可以觀察工作流是否能並行,但不能把一台 Mac 視為可無限並行的容器。要同時檢查 Runner 路由、Xcode 建置、模擬器測試和記憶體競爭。若多個 Job 只是排隊而不是同時執行,第二台 Mac 的價值在於解除排隊,而非令單一 Job 變快。

獨立開發者只用一台遠端 Mac 做 iOS CI 夠嗎?

低頻提交、測試矩陣有限,而且 Archive 可以錯峰時,一台遠端 Mac 適合作為起點。請先保存工作流歷史與 Job 日誌;如果正式發布經常被測試阻塞,或維護主機時沒有回退路徑,就應改評估第二台或短期擴容。

怎樣用 GitHub Actions 的排隊時間估算 Runner 數量?

把每個 Job 的排隊時間與執行時間按工作類型分組,再找出同一時段實際重疊的 Job。若等待集中在發布窗口,臨時增加 Runner 可能比全年常駐更合理;若日常 Pull Request 也持續排隊,才需要檢查基礎容量與工作流設計。

iOS 測試和 Archive 要不要分開使用 Mac?

當兩者使用不同簽名權限、可靠性要求或發布時限時,分開更容易控制風險。測試 Runner 可服務一般驗證,發布 Runner 使用專用標籤和隔離憑證。負載很低時可以先共用,但必須完成重啟、斷線和發布回退測試。

只在 App 發布期間增加遠端 Mac 是否更合適?

如果容量缺口只出現在固定發布窗口,按實際租用周期增加一台環境通常較合理。前提是新增 Mac 能按既定方式完成工具鏈、Runner、憑證與產物驗收,並在窗口後停止或清理,不要把臨時方案變成無人管理的常駐主機。

05

第一週執行:把排隊紀錄變成容量決策卡

以下流程不要求先購買第二台 Mac。先收集資料,再決定配置。

第一步:建立 Job 分類

把工作流中的 Job 標成 buildtestarchiveuploadservice-wait。不要只記 Workflow 名稱,否則無法知道到底是哪一類工作占用 Runner。

第二步:保存四個時間點

從工作流歷史、Job 日誌及 Actions 指標中記錄:

  • Job 進入佇列的時間。
  • Runner 開始執行的時間。
  • Xcode 建置或測試開始及結束的時間。
  • Archive 完成、上傳完成及服務端處理結束的時間。

GitHub 的 Actions 指標文件 可作為觀察執行與排隊資料的入口。若帳戶沒有組織級指標,就用工作流歷史、Job 日誌及 workflow_job 事件自行保存;不要用每日建置總數代替排隊資料。

第三步:標記峰值重疊

在同一時間軸上標出 Pull Request 測試、定時測試和發布 Job。重點不是一天執行多少次,而是同一時間有多少個 Job 需要同一類 Mac 資源。

第四步:先處理工作流浪費

檢查依賴快取、重複觸發、過時提交和不必要的測試矩陣。對於會影響發布的併發設定,先決定哪些舊 Job 可以取消,哪些 Archive 必須保留。不要用增加 Mac 的方式掩蓋每次執行都重複做同一件事的問題。

第五步:設定 Runner 邊界

至少建立測試與發布兩個邏輯用途。為發布 Runner 設定專用標籤,限制簽名憑證的使用範圍,並確認普通 Pull Request 不會誤用生產環境。

第六步:做故障回退演練

單機方案要測試斷線、重啟後 Runner 能否回來,以及未完成 Job 如何處理。雙機方案要驗證任務路由、簽名隔離和其中一台不可用時的發布路徑。彈性擴容方案則要驗證新 Mac 從交付到可接收 Job 的實際步驟。

Apple 的 測試結果說明文件 可用來核對測試產物與結果;完成 Archive 後,還應依照 App Store Connect 上傳建置說明 驗證上傳結果,而不是只看 Runner 顯示成功。

06

最終判斷:單機、雙機或按需擴容

完成上述記錄後,用以下決策卡收斂結果:

  • [ ] 我已按 Job,而不是按開發者人數或每日建置次數,整理負載。
  • [ ] 我已分開排隊時間、Runner 執行時間與 App Store Connect 後台等待。
  • [ ] 我已找出發布窗口的峰值重疊,而不是只看平均利用率。
  • [ ] 我已取消過時驗證,並排除依賴下載和無效測試造成的假性瓶頸。
  • [ ] 我已將測試、Archive、簽名和上傳按安全等級分流。
  • [ ] 單機方案已通過斷線、重啟和發布回退測試。
  • [ ] 雙機方案已驗證標籤路由、憑證隔離和單台故障時的發布能力。
  • [ ] 彈性方案已確認新增遠端 Mac 的交付、初始化和停止流程。
  • [ ] 我已寫下停止條件:什麼情況下繼續優化工作流,什麼情況下增加常駐 Mac,什麼情況下只在發版期間租用。

判斷可以簡化成三種結果:

  • 單機:單人低頻、峰值重疊少,排隊不影響發布,且故障後有可接受的恢復流程。
  • 雙機:測試與發布經常重疊,或發布不能等待普通 Job 完成;第二台主要提供並行和回退。
  • 按需擴容:缺口只在測試高峰或發布窗口出現,平日沒有足夠負載支撐常駐硬體。

如果目前方案是自購一台長期閒置的 Mac,常見缺點是硬體成本被固定、主機維護和重啟需要自行處理,而且單一主機故障會同時影響測試與發布。若改用一般雲端環境,又可能遇到 macOS 工具鏈、簽名權限、連線穩定性和環境一致性的額外管理工作。對於只在波峰缺少並行容量的專案,使用 MESHLAUNCH 租用遠端 Mac,先按實際周期增加一台環境,再完成 Runner、憑證與回退驗收,通常比立即購入全年閒置硬體更貼近真實負載。您可以先查看 遠端 Mac 的可用方案,再按工作流資料決定租用周期;若要比較特定 Mac 配置,也可參考 Mac mini 遠端訂購選項