GitHub Actions 步驟怎麼平行執行?用 background、wait 與 parallel
GitHub Actions 以前若要在同一個 job 同時跑兩個命令,常見做法是在 shell 裡加 &,再自己處理 PID、log 和退出碼。現在 workflow syntax 提供 background、wait、wait-all、cancel 與 parallel,可以把「同時開始」和「什麼時候算完成」寫在 YAML 裡。
先給選擇結論:獨立工作而且要一起結束,用 parallel;長時間服務要陪跑,用 background: true,再用健康檢查、wait 或 cancel 管理;需要不同 runner、作業系統或權限時,改用 job、matrix 與 needs。
先選對並行邊界
| 需求 | 適合的語法 | 下一步如何發生 |
|---|---|---|
| 多個互不依賴的 build 一起跑 | parallel | 群組內全部完成後才繼續 |
| 啟動 server、database 或 monitor | background: true | job 先往下走,之後明確同步或停止 |
| 等一個或幾個背景步驟 | wait | 指定的步驟完成後,輸出與失敗狀態可被後續讀取 |
| 等所有背景步驟 | wait-all | 全部完成後才繼續 |
| 不再需要長時間程序 | cancel | 發出終止訊號並讓程序清理 |
GitHub 文件目前規定同一個 job 最多同時執行 10 個 background steps;超出的步驟會等待可用名額。這是 runner 的步驟並行限制,不是整個 repository 的 Actions concurrency 設定。若你要限制不同 workflow run 不要互相取消,請另外看 GitHub Actions concurrency 與部署佇列。
用 parallel 跑獨立工作
parallel 適合一組自包含、互不寫入同一個輸出目錄的工作:
name: Build components
on: push:
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6
- parallel: - name: Build frontend run: npm run build:frontend - name: Build backend run: npm run build:backend - name: Build documentation run: npm run build:docs
- name: Run integration tests run: npm test這三個步驟會同時啟動,parallel 內建等待全部完成;其中任何一個失敗,後面的 integration tests 不應繼續。它們仍共享同一個 job 的工作目錄與環境,所以如果三個命令會改同一個檔案、搶固定 port 或共用不可並行的資料庫,就不能只因為語法短而放進同一組。
需要分開 runner、不同 Node/OS、不同權限或獨立 cache 時,應改成多個 job。parallel 不會替每個步驟建立新的 runner。
用 background 讓服務陪跑
背景步驟適合 server、database 或測試監控器。啟動後先用獨立的健康檢查確認服務可以連線,再執行測試,最後用 cancel 收尾:
steps: - uses: actions/checkout@v6
- name: Start preview server id: preview run: npm run preview background: true
- name: Wait for preview health run: ./scripts/wait-for-preview.sh
- name: Run browser tests run: npm run test:e2e
- name: Stop preview server cancel: previewbackground: true 只表示 job 不會在這個步驟停住,不表示 port 已經 ready。如果 server 啟動失敗,應在下一個 wait 或 wait-all 對它做同步,或讓 health check 明確失敗;不要用「測試連不上」才間接猜測 server 問題。對預期永遠不會自行結束的服務,不要把 wait: preview 放在測試之後,否則 job 會一直等到服務結束。
如果同時要啟動 database、cache 和 mock server,可以用多個 background steps,再用 wait-all 等它們結束;但服務 readiness 仍要由 health check 驗證:
steps: - name: Start database id: database run: docker run --rm --name ci-db postgres:15 background: true
- name: Start cache id: cache run: docker run --rm --name ci-cache redis:7 background: true
- name: Run integration tests run: npm run test:integration
- name: Stop services cancel: database
- name: Stop cache cancel: cache真正的 workflow 還應處理 credentials、health check 和失敗時的 cleanup;這裡的重點是把程序生命週期寫成可審查的步驟。
需要等待輸出時用 wait
wait 不執行命令,只等待被指定的 background step。背景步驟的 outputs 和 environment changes,也要在對應的 wait 或 wait-all 之後才交給後續步驟:
steps: - name: Build frontend id: frontend run: npm run build:frontend background: true
- name: Build backend id: backend run: npm run build:backend background: true
- name: Run lint while builds run run: npm run lint
- name: Wait for both builds wait: [frontend, backend]
- name: Package release run: npm run package如果 frontend build 失敗,wait 會把失敗帶到這個同步點;不要在同步前讀取它尚未完成的 $GITHUB_OUTPUT。需要等所有正在執行的背景工作時,才用不帶參數的 wait-all。
為什麼不要把 & 當成預設解法
舊寫法如下:
npm run preview &npm testforeground command 成功時,shell 可能先回傳成功,背景程序稍後才失敗;兩者的 log 也容易混在一起,清理則要自己保存 PID。若 runner 版本或既有流程真的只能使用 shell backgrounding,至少要做明確的 health check、wait 與 trap cleanup;能使用新 workflow syntax 時,讓 runner 知道哪些步驟是背景工作會更容易追查。
這和 GitHub Actions workflow execution protections 是不同層次:本文處理 job 內的步驟生命週期,權限與誰能觸發 workflow 仍要另外設定。
合併前用小型 workflow 驗證
第一次導入時,不要直接把 production deploy 改成平行流程。可以先驗證:
- 兩個步驟各自寫入不同檔案,從 log 確認它們確實重疊執行。
- 讓其中一個背景步驟回傳非零,確認
wait或parallel群組會失敗。 - 讓背景 server 在測試前啟動失敗,確認 health check 能直接指出原因。
- 檢查平行步驟沒有同時寫入同一路徑或搶同一個 port。
- 確認測試失敗時仍會停止 server、database 和 monitor。
- 需要隔離 runner 或矩陣版本時,改用 matrix/job,不要把隔離責任塞進 step。
把依賴關係寫出來,並行才不會只是縮短 YAML 的方式:parallel 管理一組獨立且會結束的工作,background 管理仍在運作的程序,wait/wait-all 回收結果,cancel 負責停止不再需要的服務。
常見問題
Q: GitHub Actions 要怎麼同時執行多個步驟?
A: 把互不依賴的步驟放進 parallel 群組。GitHub 會同時啟動它們,並在全部完成後才進入下一步;需要不同 runner 或作業系統時,改用多個 job 或 matrix。
Q: background 和 parallel 有什麼差別?
A: parallel 是一組步驟的便利語法,會在群組結束時自動等待全部完成;background: true 是單一步驟的細粒度控制,適合服務、監控器或需要稍後用 wait、wait-all、cancel 管理的長時間程序。
Q: background step 的 output 何時能給下一步使用?
A: 等對應的 wait 或 wait-all 完成後,該 background step 的 outputs 和 environment changes 才可供後續步驟使用。啟動不等於已完成,也不等於 output 已準備好。
Q: 同一個 job 可以同時跑幾個 background steps?
A: GitHub Actions 目前文件列出同一個 job 最多同時執行 10 個 background steps;超過的會排隊。這個限制不等於 job 或 workflow 層級的 concurrency 設定。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。