第34章|GitHub Actions 矩阵与并行:多版本、多平台测试

矩阵是“用维度换覆盖面”:一次把 OS × 语言版本 × 架构 × 实验组合成一张可执行的测试网格。 并行与 fail-fastmax-parallelconcurrency 一起决定:你跑得快不快、花多少钱、以及失败时是否“立刻止损”。

Matrix

维度展开

  • strategy.matrix
  • include / exclude
  • matrix.context in job
Parallel

并行与资源

  • max-parallel
  • runner minutes
  • queue vs fan-out
Control

失败与取消

  • fail-fast
  • concurrency 去重
  • 命名 job 便于排障

1. 矩阵在做什么:笛卡尔积,不是“拍脑袋多写几条”

strategy.matrix 把多个维度组合成多条独立 job(每个组合一个矩阵向量)。 若 os: [ubuntu-latest, windows-latest]node: [18, 20], 通常会得到 2 × 2 = 4 条并行任务(除非你用 exclude 缩小)。

提示:矩阵越大,分钟数与队列时间越可能膨胀;矩阵是“测试策略”,不是“越多越好”。
Matrix fan-out: 2 OS × 2 Node = 4 jobs Each cell is one matrix job; GitHub runs them in parallel subject to runner capacity node / rows ubuntu-latest windows-latest 18 20 job ubuntu + node18 job windows + node18 job ubuntu + node20 job windows + node20
图 1:矩阵 = 维度组合。每个格子是一条独立 job;并行度受 runner 配额与 max-parallel 约束。

2. 最小可用:matrix + runs-on + 使用 matrix 上下文

runs-on 通常取自 matrix.os, 步骤里用 matrix.node / matrix.python-version 选择工具链版本。 在 setup-node 等 action 里传入对应版本。

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [18, 20]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci
      - run: npm test

3. include 与 exclude:从“全组合”里裁剪出真实需求

include 追加一组额外向量,或覆盖字段(例如某些组合用不同 runs-on)。 exclude 从笛卡尔积中剔除组合,避免无意义或重复跑。

Full cartesian product → exclude → runnable set full matrix all combinations exclude drop invalid pairs e.g. win + old jdk final jobs + optional include
图 2:exclude 缩小无效组合;include 追加特殊向量或覆盖字段(例如自定义 runner)。

4. fail-fast:第一次失败就停,还是“收集全部失败”?

strategy.fail-fast: true(默认)时,矩阵中任一 job 失败会取消同一 matrix 中仍为 queued / in progress 的兄弟 job。 设为 false 时更适合“想看清所有组合的红灯”,但会消耗更多分钟数。

fail-fast: first failure stops siblings FAIL cancelled sibling job cancelled fail-fast=true: stop the queue early; fail-fast=false: run to completion
图 3:fail-fast 控制“失败后的兄弟 job 是否继续跑”。默认偏快止损;需要全量矩阵报告时改为 false

5. max-parallel:限制同时跑的矩阵行数

strategy.max-parallel 限制同一 matrix job里最多同时执行多少个矩阵向量(常用于控制 burst、避免排队拖垮组织配额)。 与 workflow 级 concurrency(同一 PR 或分支去重)是不同层面的旋钮。

max-parallel: runner slots vs waiting queue running (max-parallel = 2) RUN RUN queued queued workflow concurrency: different knob; cancel duplicate runs
图 4:max-parallel 控制矩阵并行上限;其余 job 排队。与 concurrency(去重/取消旧 run)是两套机制。

6. 命名与可观测性:让 Required checks 一眼能对上

在 job 或 step 上设置 name:,把 matrix.osmatrix.node 写进名字, 分支保护里的 Required checks 才能与具体组合对齐(避免“都叫 test”却不知道哪一格红)。

jobs:
  test:
    name: test (${{ matrix.os }}, node ${{ matrix.node }})
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [18, 20]
    runs-on: ${{ matrix.os }}

7. 最小清单

  1. 先列维度:OS / 语言版本 / 架构;再算组合数,必要时 exclude
  2. 明确 fail-fast:要快止损还是全量矩阵报告。
  3. max-parallel 控制突发并行;用 concurrency 控制重复 run。
  4. name: 把矩阵维度写进 job 名,便于合并门禁与排障。
← 上一章:缓存与制品(cache / artifact) 下一章:Secrets 与 OIDC →