雙端扇出 · Gradle/CocoaPods/DerivedData 分層 · 佇列門檢與回退單節點
維護Flutter或React Native單倉的小團隊在多台Mac Mesh遠端節點上同時跑 iOS 與 Android 時,常被快取互踩、佇列飢餓與跨區拉套件拖垮 wall time。本文給出串列、雙節點扇出與專用端節點的決策矩陣,拆解 Gradle、CocoaPods、DerivedData 的分層鍵與唯讀消費邊界,並附六步可復現門檢與回退到單節點的條件。可與Monorepo 影響範圍建置、跨區產物分發矩陣交叉閱讀。
雙端並行並非把兩條流水線綁在同一台機器上同時跑;若磁碟與 CPU 爭用未被建模,「並行」會把 flaky 從編譯器搬進排程器。下列訊號出現時,應優先回到決策矩陣而不是繼續加並發。
Gradle 與 Xcode 爭用磁碟:同一節點上 ~/.gradle 與 DerivedData 同步膨脹,IO 等待主導 wall time。
CocoaPods 解析與 Android NDK 版本漂移:鎖檔未進快取鍵時出現「遠端綠、整合紅」的假命中。
Metro 與模擬器爭用:RN 互動驗證與 CI 無人值守任務搶同一套 CPU 核心,佇列深度上升但吞吐下降。
扇出無唯讀邊界:消費節點回寫共用前綴,半同步寫入與雙端產物指標切換競態。
跨區拉快取無逾時預算:網路類重試無限放大,佔用並發席位導致飢餓。
下列維度面向多地區遠端 Mac 資源池上的跨端行動單倉;目標是讓「是否扇出」成為可稽核欄位。若倉庫同時包含 heavy native 模組,請先對照影響範圍建置文中的全量短路條件。
| 維度 | 優先單節點串列 | 優先雙節點扇出 | 拆專用端節點 |
|---|---|---|---|
| 變更形態 | 僅單端資源或文案微調 | 兩端同時 bump 依賴或二進位介面 | Android 需多 ABI 矩陣且 iOS 需 Archive 分發並行視窗 |
| 佇列健康 | 深度穩定、P95 wall time 可預測 | 雙端排隊時間之和大於扇出節省值 | 一端 Archive 阻塞另一端 PR 驗證 |
| 快取策略 | 單前綴即可,鍵包含鎖檔與工具鏈指紋 | iOS 與 Android 使用獨立寫入前綴,消費唯讀 | 端專用節點使用獨立世代號與租約 id |
| 跨區 | 單區域可滿足 SLA | 主區寫入、衛星唯讀鏡像 | 衛星區禁止回寫任一端前綴 |
| 回退 | 佇列溢出或磁碟告警時合併為串列 | 校驗失敗連續兩次則凍結扇出 | 大版本 Xcode 或 AGP 切換視窗強制單端獨佔 |
先凍結「可復現輸入」再談雙端並行;順序反了會把並行度變成並行故障。
以下步驟假設 Runner 已能穩定登入各節點並完成共享池互信;若產物需跨洋扇出,請同步落實產物分發文中的 manifest 與租約欄位。
凍結輸入五元組:提交短雜湊、Podfile.lock/Gemfile.lock、Gradle 鎖、xcodebuild -version 與 Android SDK/NDK 主版本寫入流水線頭。
拆分寫入前綴:IOS_CACHE_GEN 與 AND_CACHE_GEN 單調遞增;禁止雙端共用同一寫入目錄。
判定扇出:命中決策表「優先雙節點扇出」對應欄位時建立並行 job graph,否則串列。
主建置寫入、消費唯讀:僅主節點寫 tarball;消費節點校驗雜湊與大小雙欄位後再解壓。
佇列預算:為網路類錯誤設定指數退避與硬上限;超過上限記入 incident 並釋放席位。
回退單節點:磁碟或佇列超閾時自動合併為串列並打標 FANOUT_DISABLED 供覆盤。
IOS_KEY="${CI_COMMIT_SHORT_SHA}:pods:${PODFILE_LOCK_SHA}:$(xcodebuild -version | shasum -a 256 | cut -c1-10)"
AND_KEY="${CI_COMMIT_SHORT_SHA}:gradle:${GRADLE_LOCK_SHA}:${ANDROID_SDK_MAJOR}"
export FASTLANE_SKIP_UPDATE_CHECK=1
echo "{\"ios\":\"$IOS_KEY\",\"android\":\"$AND_KEY\"}" > "${CI_PROJECT_DIR}/dual-cache.manifest"
提示:鍵欄位可依團隊棧替換為自訂 manifest;關鍵是單調世代與端隔離寫入前綴,不要在消費機重複解析相依圖。
下列數值為審查與容量規劃起點,須以你們倉庫真實建置時長直方圖與佇列指標替換;不得直接宣稱為對外 SLA。覆盤時應同時給出雙端 P95、快取 tarball 展開耗時與席位佔用時長三條序列。
FANOUT_DISABLED 與人工巡檢,而不是繼續並行。| 團隊規模訊號 | 推薦起步策略 | 與產物扇出關係 |
|---|---|---|
| 個位數貢獻者 | 單區域串列雙端+本機快取 | 扇出需求低,鍵可簡化 |
| 多地區並行 PR | 主區寫雙前綴+衛星唯讀 | 與 rsync 或物件儲存扇出強耦合 |
| AI Agent 夜間任務 | 專用重編譯節點與互動池隔離 | 避免夜間批次任務打爆共享鍵空間 |
注意:在未關閉消費節點寫入權限前開啟跨區扇出,會把半同步問題放大為「多地同時假綠」。
依賴個人筆電同時承擔 Android 模擬器與 iOS Archive,常在休眠、鎖定螢幕與頻寬波動上同時欠帳;純 SaaS 行動建置則在原生除錯與企業內網策略上頻繁碰壁。對要把雙端持續交付與可稽核節點角色放在同一容量故事裡的團隊,自建拼湊方案在觀測與權限邊界上持續失血。
相較之下,需要合約化節點、可覆核頻寬與區域可選的團隊,把關鍵雙端建置跑在可訂購的雲端 Mac 與配套佇列策略上更利於落地門檢;對同時承擔跨端交付與 AI Agent 夜間負載的情境,VpsMesh 的 Mac Mini 雲端租賃通常是更優解:節點可拆分、鏈路可稽核,讓並行度與佇列深度同樣可驗收。
當 wall time 被兩條鏈路同時拉長、單節點 IO 或模擬器與 xcodebuild 爭用明顯,或佇列深度持續高於閾值時優先扇出;若變更集中在單端可先串列。更多裁剪邏輯見Monorepo 影響範圍建置文。
不建議無隔離共用寫入前綴;應分層鍵與目錄並保證主建置寫入、消費唯讀。跨區扇出請同步閱讀產物分發矩陣。