fix(runner): v5 - Job 層級 mutex 確保嚴格序列執行

根因確認:
- 即使有 needs 依賴,Jobs 仍可能在 "Set up job" 階段並行
- 所有 Jobs 共用同一 Runner,並行寫入 _diag/pages 造成衝突

永久解決方案:
- 每個 Job 加上 concurrency.group: runner-awoooi-cd-mutex
- cancel-in-progress: false (等待而非取消)
- 確保同一時間只有一個 Job 在 Runner 上執行

影響:
- CD 會變慢 (Jobs 嚴格序列)
- 但保證穩定性 (不再有檔案衝突)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
OG T
2026-03-29 02:12:38 +08:00
parent 07114f9181
commit 6ddaf75260

View File

@@ -57,6 +57,11 @@ jobs:
name: "Pre-flight Check"
runs-on: [self-hosted, harbor, k8s]
timeout-minutes: 1
# 2026-03-29: Runner 全局 mutex確保同一 Runner 不會並行執行任何 CD Job
# 使用固定 group 名稱 (非 run_id),所有 CD Jobs 共用同一把鎖
concurrency:
group: runner-awoooi-cd-mutex
cancel-in-progress: false
steps:
# =======================================================================
# 2026-03-29: Runner _diag/pages 檔案衝突修復 (v3)
@@ -130,6 +135,9 @@ jobs:
runs-on: [self-hosted, harbor, k8s]
needs: pre-flight-check
timeout-minutes: 1
concurrency:
group: runner-awoooi-cd-mutex
cancel-in-progress: false
outputs:
api: ${{ inputs.force_deploy == true && 'true' || steps.filter.outputs.api }}
web: ${{ inputs.force_deploy == true && 'true' || steps.filter.outputs.web }}
@@ -168,7 +176,10 @@ jobs:
name: "Build API"
runs-on: [self-hosted, harbor, k8s]
needs: detect-changes
timeout-minutes: 20 # 2026-03-29: 增加超時時間 (Docker Build 需要更長時間)
timeout-minutes: 20
concurrency:
group: runner-awoooi-cd-mutex
cancel-in-progress: false
if: |
!inputs.skip_api && (
needs.detect-changes.outputs.api == 'true' ||
@@ -208,7 +219,10 @@ jobs:
name: "Build Web"
runs-on: [self-hosted, harbor, k8s]
needs: detect-changes
timeout-minutes: 20 # 2026-03-29: 增加超時時間 (Next.js Build 需要更長時間)
timeout-minutes: 20
concurrency:
group: runner-awoooi-cd-mutex
cancel-in-progress: false
if: |
!inputs.skip_web && (
needs.detect-changes.outputs.web == 'true' ||
@@ -261,6 +275,9 @@ jobs:
runs-on: [self-hosted, harbor, k8s]
needs: [detect-changes, build-api, build-web]
timeout-minutes: 10
concurrency:
group: runner-awoooi-cd-mutex
cancel-in-progress: false
if: always() && (needs.build-api.result == 'success' || needs.build-api.result == 'skipped') && (needs.build-web.result == 'success' || needs.build-web.result == 'skipped')
environment: production
steps: