1684 字
8 分鐘

GitHub Actions 步驟怎麼平行執行?用 background、wait 與 parallel

GitHub Actions 以前若要在同一個 job 同時跑兩個命令,常見做法是在 shell 裡加 &,再自己處理 PID、log 和退出碼。現在 workflow syntax 提供 backgroundwaitwait-allcancelparallel,可以把「同時開始」和「什麼時候算完成」寫在 YAML 裡。

先給選擇結論:獨立工作而且要一起結束,用 parallel;長時間服務要陪跑,用 background: true,再用健康檢查、waitcancel 管理;需要不同 runner、作業系統或權限時,改用 job、matrix 與 needs

先選對並行邊界#

需求適合的語法下一步如何發生
多個互不依賴的 build 一起跑parallel群組內全部完成後才繼續
啟動 server、database 或 monitorbackground: truejob 先往下走,之後明確同步或停止
等一個或幾個背景步驟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: preview

background: true 只表示 job 不會在這個步驟停住,不表示 port 已經 ready。如果 server 啟動失敗,應在下一個 waitwait-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,也要在對應的 waitwait-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

為什麼不要把 & 當成預設解法#

舊寫法如下:

Terminal window
npm run preview &
npm test

foreground 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 改成平行流程。可以先驗證:

  1. 兩個步驟各自寫入不同檔案,從 log 確認它們確實重疊執行。
  2. 讓其中一個背景步驟回傳非零,確認 waitparallel 群組會失敗。
  3. 讓背景 server 在測試前啟動失敗,確認 health check 能直接指出原因。
  4. 檢查平行步驟沒有同時寫入同一路徑或搶同一個 port。
  5. 確認測試失敗時仍會停止 server、database 和 monitor。
  6. 需要隔離 runner 或矩陣版本時,改用 matrix/job,不要把隔離責任塞進 step。

把依賴關係寫出來,並行才不會只是縮短 YAML 的方式:parallel 管理一組獨立且會結束的工作,background 管理仍在運作的程序,waitwait-all 回收結果,cancel 負責停止不再需要的服務。

常見問題#

Q: GitHub Actions 要怎麼同時執行多個步驟?#

A: 把互不依賴的步驟放進 parallel 群組。GitHub 會同時啟動它們,並在全部完成後才進入下一步;需要不同 runner 或作業系統時,改用多個 job 或 matrix。

Q: backgroundparallel 有什麼差別?#

A: parallel 是一組步驟的便利語法,會在群組結束時自動等待全部完成;background: true 是單一步驟的細粒度控制,適合服務、監控器或需要稍後用 waitwait-allcancel 管理的長時間程序。

Q: background step 的 output 何時能給下一步使用?#

A: 等對應的 waitwait-all 完成後,該 background step 的 outputs 和 environment changes 才可供後續步驟使用。啟動不等於已完成,也不等於 output 已準備好。

Q: 同一個 job 可以同時跑幾個 background steps?#

A: GitHub Actions 目前文件列出同一個 job 最多同時執行 10 個 background steps;超過的會排隊。這個限制不等於 job 或 workflow 層級的 concurrency 設定。

參考資料:

GitHub Changelog:Actions steps can now be run in parallel

GitHub Docs:Workflow syntax for GitHub Actions

GitHub Actions 步驟怎麼平行執行?用 background、wait 與 parallel
https://laplusda.com/posts/github-actions-parallel-steps/
作者
Zero
發佈於
2026-08-17
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。