GitHub Actions "concurrency" とは
CI安定化
最近、RowicyのCIを少し安定させるための修正を行った
pnpmのバージョンを固定し、pnpm installを--frozen-lockfileするのが目的
付加的に、concurrencyを追加した
concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true...concurrencyとはなんだろか
concurrencyとは
GitHub Actionsでは、同じブランチへの複数pushするとCIインスタンスはその度に起動し、各々のタイミングで開始し完了まで走る
しかしlintやテストは最新コミットのCI結果を見れば十分で
古いJobを完了まで走らせるよりはキャンセルしちゃったほうがいい
Job ───────× ↑ │ │Job ▶ ─────────────────────これにはconcurrencyキーが使える
concurrency: group: test cancel-in-progress: truegroupの指定
並行制御グループをつくる
concurrency: group: hogeと書けば、これがグルーピング指定
名前は何でもいい
しかしこうすると、Jobはすべてhogeグループになる
コミット先ブランチ、ワークフロー関係なく
なので変数でわける
name: 'Test'
concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: trueこれでTestワークフローならTest-refs/heads/<branch>というgroup名になり
他ブランチのCIがJobをキャンセルすることはない
cancel-in-progress
キャンセル制御をグループと合わせて宣言
グループ内で新しいJobがきたら、今走っているJobはどうするかを宣言
cancel-in-progress: true
Job ───────× ↑ │ │Job ▶ ───────────────────── ✓cancel-in-progress: false
Job ──────────────── ✓ ↑ │ │Job ----wait--- ▶ ───────────────────── ✓| 設定 | 挙動 | ユースケース | 例 |
|---|---|---|---|
cancel-in-progress: true | 中断 | 最新のコミットのみ実行でいい | - PR 毎のテスト - lint / 単体テスト - ビルド確認 |
cancel-in-progress: false | 中断せずに、新しい実行を待機 | 途中でキャンセルされると困る | - 本番デプロイ - データ移行ジョブ - 夜間バッチ処理 |
待機は1件のみ
cancel-in-progress: falseのとき
待機できるのは最新の1件のみ
ここでqueue: maxつけると最大100件まで待機させられる
concurrency: group: deploy cancel-in-progress: false queue: max今回は必要がなかったのでつけてない
WorkflowにもJobにも設定できる
GitHub ActionsではWorkflowにJobが含まれる
Workflow└── jobs └── <job_name> ├── runs-on └── steps並行制御のグルーピングはWorkflow単位とJob単位でできる
concurrencyの階層を変えるだけ
- Workflow
name: 'Test'
concurrency: group: hoge cancel-in-progress: true
jobs: ...- Job
name: 'Test'...
jobs: test: concurrency: group: hoge cancel-in-progress: trueGitLab CI
GitLab CIにも同様のキャンセル機能があるが少し制御が異なる
workflow: auto_cancel: on_new_commit: interruptible #キャンセル判断をワークフローで指定
stages: - test
unit_test: interruptible: true # 割り込みOK stage: test script: - npm run test
integration_test: interruptible: true # 割り込みOK stage: test script: - npm run test:e2eGithubとちがい、ワークフローレベルでワークフローのキャンセル判断を指定
Job側でキャンセル可否を宣言する
キャンセル判断とはon_new_commitの値だが以下が指定できる
| 設定値 | 動作 | 主なユースケース |
|---|---|---|
| interruptible | 割り込み可能OKと言ってるJobあったらキャンセルして | テストやビルドは途中で止める |
| conservative | 割り込み可能NGのJobあったら最後まで完了させて | 不整合を極力避けたい |
| none | キャンセル判断なし | 無設定と同じ |
これに対してJob側でinterruptibleを指定
キャンセルされて構わないかどうかを指示する
ここでconservativeを指定するとGitHubの cancel-in-progress: false のように待機列に入るかというとそうではない
Jobはキャンセルされず完了まで各々走るだけ
on_new_commitの指示に待機列は関係ない
resource_group
Jobの同時実行数制御はresource_groupで行う
deploy_production: stage: deploy script: - ./deploy.sh resource_group: productionresource_groupが同じJobは直列に実行される
deploy_productionジョブが複数発生しても順番に実行される
Githubは並行制御用グルーピングだったが、Gitlabは直列実行用グルーピングであることに注意
キューと同等
GithubとGitlabのJob制御の違い
GitHubとGitLabでは並行制御とグルーピングの考え方が違う
GitHubはWorkflow, Job単位でグルーピング、そこでキャンセルか、直列実行
GitLabはWorkflowでキャンセル判断を示すがキャンセルの意思表示はJob側で 直列実行はまた別でJob側でグルーピング指定
こんな感じに分けられる