并发控制与管道取消
限并发管道运行并取消被取代的运行、使 CI 资源花在最新提交非将被推过的旧提交。
为什么
无并发控制、开发者连推 5 提交触发 5 管道运行、全并行对已过时提交 1-4 跑——CI 烧 5 倍算力为无人读的结果、且第 5 运行(重要的)排 4 旧运行后更慢。并发控制在新提交推时取消旧运行、使仅最新提交管道跑——这减半 CI 账单、加速最新提交反馈、释放运行器给其他 PR。部署管道同理: 部署进行中新 部署触发时、旧的应取消(非并行跑、可坏发布)。机制是按分支(或 PR)键的并发组、cancel-in-progress: true。
何时使用
CI 运行器为共享有限资源时——本质总如此。团队有超几并发 PR 或 CI 分钟为计费资源时此控制变关键。
如何做
1. 给每工作流加并发组
- 按分支(或 PR 号)键使不同分支运行不互取消
- 设 cancel-in-progress: true 使新运行取消同分支前一运行
2. PR 和 push 用不同组
- PR 运行: 并发组 "pr-${{ github.event.pull_request.number }}"
- main 运行: 并发组 "main"(勿取消——每 main 运行为部署候选)
3. 取消旧矩阵 job
- 矩阵构建(如 5 OS × 3 Node 版 = 15 job)中跑取消释放 15 运行器
- 新提交推时并发组取消整个矩阵
4. 勿取消部署管道
- 部署管道用 cancel-in-progress: false(进行中部署应完成、非中部署取消)
- 或部署用单独并发组最大 1
5. 监取消率
- 高取消率(> 50%)示开发者推太频——考虑本地跑 lint 的 pre-commit hook
- 低取消率(< 5%)示并发控制未抓旧运行——查组键示例
# .github/workflows/ci.yml — 取消旧 PR 运行
name: ci
on:
pull_request:
branches: [main]
concurrency:
group: pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm test
# .github/workflows/deploy.yml — 勿取消部署
name: deploy
on:
push:
branches: [main]
concurrency:
group: deploy-production
cancel-in-progress: false # 让当前部署完成常见问题
- ⚠PR 运行并发组键 github.ref——所有 PR 共享同 ref(refs/pull/N/merge)、故一 PR 运行取消另一 PR 运行、开发者见 CI 消失无解释。
- ⚠部署工作流设 cancel-in-progress: true——生产部署被新推 main 中途取消、留服务半部署状态新旧代码混。
- ⚠完全不用并发控制——开发者调试时推 10 提交、10 管道运行并行、CI 账单升、第 10 运行(重要的)慢因运行器忙于 9 旧运行。
- ⚠取消最后几秒运行(传产物、发评论)——取消失产物和评论、开发者须重跑管道得测试报告。
最佳实践
- ✓PR 并发组键 PR 号(github.event.pull_request.number)非 github.ref——这确保每 PR 运行仅取消该 PR 旧运行。
- ✓CI 工作流(lint、test、build)设 cancel-in-progress: true、部署工作流设 false——CI 运行便宜可重复、部署贵须原子完成。
- ✓取消前加短宽限期(平台支持时)使最后几秒运行可完成传产物——这保留最新运行测试报告。
- ✓同监取消率和运行器利用率——高取消率低利用率示组键错(运行应取消时未取消)。