導入:なぜConcurrency制御が必要なのか?
GitHubで共同開発をしていると、プルリクエスト(PR)に対して立て続けにコミットをpushすることがよくありますよね。そのたびにCI(GitHub Actions)が動き出し、古いコミット用のジョブが実行され続けてしまうことはありませんか?
実はこれ、非常に「もったいない」状態です。古いジョブは結果を見ないまま破棄されることがほとんどですし、何よりGitHub Actionsの無料枠を無駄に消費したり、他のメンバーのジョブがキューで詰まって開発効率を下げたりする原因になります。今回紹介する「Concurrency制御」を使えば、最新のコミット以外のジョブを自動キャンセルし、効率的な開発環境を作ることができます。
基礎知識:Concurrencyとキャンセル処理
GitHub Actionsにおけるconcurrencyとは、同時に実行されるジョブの並列数を制御する仕組みです。
通常、設定しなければすべてのコミットに対して個別にジョブが立ち上がりますが、この設定を入れることで「同じグループ内では一度に一つのジョブしか動かさない」という制限をかけられます。
さらに、cancel-in-progress: trueというオプションを組み合わせることで、新しくジョブが開始された瞬間に、現在実行中の古いジョブを自動的に停止させることが可能です。
実装:設定手順
設定は非常に簡単です。GitHub ActionsのYAMLファイル(.github/workflows/配下のファイル)のトップレベルに、以下の設定を追加するだけです。
ポイントは、グループ名(group)に「ブランチ名」や「PRの番号」などの識別子を指定することです。これにより、PR単位でジョブの重複を制御できるようになります。
サンプルプログラム:推奨の設定例
以下のコードを、お使いのワークフローファイルの冒頭に追加してください。
name: CI Pipeline
concurrencyの設定を記述します
concurrency:
# グループ名を指定します。github.refを指定することで、ブランチごとに排他制御を行います
# PRの場合は pull_request.head.ref を使うとより正確です
group: ${{ github.workflow }}-${{ github.ref }}
# 新しいジョブが開始されたら、同じグループ内の古いジョブをキャンセルします
cancel-in-progress: true
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: テスト実行
run: echo “ここにビルドやテストのコマンドを記述します”
応用・注意点:現場で気をつけるべきこと
1. グループ名の付け方に注意
グループ名が全リポジトリで共通になってしまうと、別のブランチのジョブまでキャンセルされてしまいます。必ず ${{ github.ref }} や ${{ github.head_ref }} を含めて、ブランチやPR単位でユニークになるようにしてください。
2. デプロイ時のリスク
本番環境へのデプロイジョブにこの設定を入れる場合は慎重に行ってください。もしデプロイ中にキャンセルが走ると、途中で処理が止まり、システムの状態が不整合になる可能性があります。デプロイフローでは、キャンセルさせたくないジョブにはこの設定を入れない、あるいは適切な排他制御を行うなどの工夫が必要です。
この設定を入れるだけで、開発チーム全体の「CI待ち時間」が驚くほど短縮されます。ぜひ今日から取り入れてみてください!

コメント