2026 Swift Strict Concurrency 遷移:在 Mac 雲 CI 上怎麼做對門禁——Sendable、CI-only flaky 與五步 Runbook
如果你是移動團隊技術負責人,2026 年很可能正在把工程推進到 Swift 6/Strict Concurrency 完整模式;卻頻頻遇到僅在 CI 上爆紅、本地卻很難復現這類「幽靈告警」。本文為讀者拆解三大根因、給出門禁決策矩陣與五步可抄 Runbook,並串聯站內 三種算力來源對照 與 Simulator 並行 PR 流水線 兩篇長文的可讀順序。
本文要點
1. 痛點拆解:CI-only 告警為什麼偏偏找上你
在進入 Swift Strict Concurrency(嚴格並發檢查)深水區之後,很多問題不再「一眼能修」,而是表現為:同事筆記本上靜默通過,流水線卻穩定失敗。這類現象的根往往不在業務邏輯,而在環境與任務形態差異。
- 工具鏈與時間片差異:CI Job 通常為 headless、`xcodebuild` 在無 UI Session 的條件下執行分析與索引;Swift 前端對並行調度極為敏感——當機器的節能核/性能核與本地開發機比例不同,
@MainActorisolation 推導會出現「只差一條警告就失敗」的差異。 - 緩存熱度的冰火兩重天:DerivedData/模塊緩存若在本地常駐溫熱,Swift 對部分跨模塊
Sendable約束會走快速路徑;而 CI「冷起跑」或未命中緩存時,會觸發更激進的診斷路徑,從而在門禁門檻上出現「本地不報、遠端報」。這不是編譯器玄學,是可度量的輸入差異。 - 任務分叉:Smoke / Simulator / Archive 混在同一個標籤裡:當你在 PR Checks 上用輕量 Smoke,卻把 Archive 延後到夜間任務,兩者對並發模型的驗證深度不同;若未顯式分叉,就會把「歸檔才暴露的問題」誤判為 flaky。更多矩陣拆分思路請對照 Simulator 並行與 destination 文中的表格。
2. 決策矩陣:哪個模塊先門禁、何時允許暫緩
Strict Concurrency 遷移不是「一口開關打開」;工程上更健康的姿勢是按模塊劃片 + 可審計 PR。下表把常見策略壓縮成可貼進評審模板的語言(你可以直接複製列頭到工單系統)。若團隊還在評估「算力從何而來」,可先讀另一篇站內決策長文:GitHub Runner、Xcode Cloud 與專用 Mac 雲三者對照。
| 策略維度 | 先門禁的業務信號 | 可先觀察窗的原因 | 門禁外的配套動作 |
|---|---|---|---|
| 跨團隊協作的數據模型 | 多處 UI/網絡層共享可變狀態 | 純內部工具、低風險流量 | 為該模塊拆分單獨 scheme 與-warnings-as-errors 開關 |
| Actor 邊界清晰度 | 已經出現野指針式「偶發卡住」日誌 | 僅佔少量代碼路徑的邊緣特性 | 為該路徑補最小可復現實驗與集成測試優先級 |
| 依賴庫升級節奏 | 上遊已標明 Swift 6 兼容 | 第三方尚未完成 Sendable 標註 | 用 Package 覆蓋或二進位隔離層擋在邊界外 |
| 運行時成本 | 歸檔/Test 任務耗時應進入預算表 | 僅開發期一次性腳本 | 在 CI 上對「並發檢查等級」分兩檔:PR 檔位與 nightly 檔位 |
矩陣的目的:把「感受」轉成可審計工單條件。
3. 五步 Runbook:從釘死工具鏈到壓平 flaky
- 釘死 Xcode 與
DEVELOPER_DIR:在專有 Mac Runner 上使用顯式sudo xcode-select -s或由基礎設施注入統一路徑;在任何 PR 模版中要求開發者粘貼xcodebuild -version輸出,門禁腳本再比對 semver。這樣能消掉九成「我本地預覽版你沒說」之爭。 - 分拆 Job:Smoke / Simulator / Archive 三條泳道:給每條泳道單獨的超時、重試與緩存鍵;避免把「重 Archive」綁在「輕 smoke」後拖垮開發者耐心。泳道參數語言與並發上限可直接復用 PR 並行文的清單。
- 對 DerivedData 設「軟預算 + 硬清理」:為磁碟水位設兩級閾值:軟閾觸發降級並發,硬閾觸發
rm -rf與冷啟動;把每次清理寫進指標,避免「為什麼忽然全員排隊」這種神秘事件。 - 對並發錯誤設「可診斷日誌包」:當
-warn-concurrency或完整模式失敗時,自動打包swiftc依賴圖片段、關鍵模塊接口文本與 Runner 資源視圖;要求修復 PR 必須附該包,減少來回三次都找不對模塊的尷尬。 - 把「允許的不完美」寫進 ADR:若必須暫時保留
nonisolated(unsafe)或與第三方類型共存,記錄在架構決策表裡:負責人、復盤日期、風險半徑。半年後機器人自動開 issue——這比口頭承諾更接近工程真實。
你可以在 CI YAML 中用類似片段強調工具鏈對齊(節選示意,佔位符請改成團隊 scheme):
4. 硬核參數:閾值、時間與磁碟水位
- 冷啟動首開牆鍾時間:在專有 M4/統一內存節點上,100k LOC 量級主工程的首次
swift build建議壓到不大於 420 秒(若長期飄高,多半是並發任務搶同一 NVMe——應回到 Job 分拆表)。該數字為經驗閾值,請以你團隊 backlog 校準。 - Archive Job 獨享窗口:為歸檔任務獨佔 1–2 P-core 等量算力配額,避免與它共享機器的 UI Smoke 爭搶同一溫控預算;這比盲目加並行度更能降低 flaky。
- DerivedData 軟閾:單節點 DerivedData不大於 240 GB(或磁碟的 70%)觸發自愈清理腳本;寫入 launchd plist 或由 Runner 鉤子觸發。
- 門禁復跑策略:對確認為資源爭用所致的失敗,只允許同一代碼哈希下復跑最多 1 次,防止「無限重骰」掩蓋真正的數據競爭。
若同時使用 Xcode Cloud 與專有 Runner,請參閱對照文「接縫」:強定製腳本、長期緩存或對磁碟布局苛求的歸檔,通常落到可 SSH 的專用 Mac。
5. 站內交叉索引與延伸閱讀
在閱讀順序上可先讀:三種算力來源 定 SLA,再對照 Simulator 並行;最後再用本文門禁拆模塊——避免隊列與歸檔搶同一條流水線。
6. 選型收束:為什麼 Mac 獨佔雲勝過混雜池
一些團隊把 Job 投進共享溫控與盤的「泛 Mac 池」,短期帳單好看,但一旦並發診斷與 flaky 歸檔攪在一起,排障時間會上升:拿不到獨佔 NVMe/穩定隊列/可預期溫控,就難以分清告警來自代碼還是鄰機噪聲。專門為 Apple 工具鏈調校的 Mac 雲更接近辦公室自建 Runner:**獨佔算力 + 漂移少 + SSH 習慣可沿用**;在混雜池上與鄰機搶 IO,只會累積不可測的技術債。