GitHub ActionsでCI/CDを組んでおり、terraform apply
をCDに組み込んでいる。
terraformの機能として、terraform apply
が同時に実行されるとstateがロックされ、他のユーザーが重複して処理を行なうことを防いでくれる。State Locking
ただ、terraform apply
を同時実行したり、途中で中断したりするとstateがロックされているが故にエラーになる。TerraformでState Lockエラーが発生したら
もし、CDで terraform apply
が同時実行され、エラーになると色々と面倒なことになる。CDはPRがマージされたら実行されるようにしているので、そんな同時にPRがマージされることはないと思いたいが、100%ないわけではない。なので仕組みで対策することを検討した。
concurrencyってなに?
workflowの同時実行の制御ができるパラメータ。 pushとかPRの更新とかをトリガーにしていたら、よくこんな感じでworkflowが同時実行されると思う。
このworkflowが同時実行されるという状態を制御できる。
作成したworkflow
検証用に以下のworkflow定義ファイルを作成。とりあえず使えそうなところだけ抽出して作成してみた。詳しくは公式ドキュメントを参照してほしい。
name: Concurrency Test Workflow
# 手動実行とプッシュ時に実行されるように設定
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
# cancel-in-progress: true
jobs:
test-job-1:
runs-on: ubuntu-latest
steps:
- name: Long running step
run: |
echo "Starting job..."
sleep 30
echo "Job completed"
説明
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
concurrencyではgroup
とcancel-in-progress
が設定できる。
group
concurrencyで制御するグループの設定。
${{ github.workflow }}は実行中のGitHub Actionsのworkflowの名前が入る。自分が作成したworkflowだと、”Concurrency Test Workflow”になる。
${{ github.ref }}は現在実行中のワークフローがトリガーされたブランチ名やタグ名が入る。自分が作成したworkflowだと、mainブランチへのpushがトリガーなので、refs/heads/mainが入る。
※手動実行は異なる場合があるが、ここでは説明を省く
つまり、${{ github.workflow }}-${{ github.ref }}は”Concurrency Test Workflow-refs/heads/main”となる。設定したgroupが他のworkflow定義ファイルと同じ場合、意図しないworkflowの挙動をするかもなので、リポジトリ内で一意なものにしておきたい。
大抵のユースケースでは${{ github.workflow }}-${{ github.ref }}でOKかなと思う。
cancel-in-progress
名前通りではあるが、新たにworkflowがQueueに入った場合、進行中のworkflowをキャンセルするかどうかの設定。
trueの場合は進行中のworkflowがキャンセルされ、Queueに入っているworkflowが実行される。
falseの場合は進行中のworkflowがキャンセルされず、実行中のworkflowが完了するまでQueueに入っているworkflowが実行されない。
動かしてみる
cancel-in-progress: falseの場合
まずはcancel-in-progress: falseの場合で動かしてみる。同時に2回workflowを手動実行する。
するとこんな感じで2つ目のworkflowがPendingになる。
※スクショするタイミングが悪かったので、1つ目のworkflowがQueuedになってる、、
2つ目のworkflowの中を見てみるとこんな表示になっている。
“This workflow is waiting for Concurrency Test Workflow to complete before running. Learn more about concurrency.”と表示され、実行中のworkflowの完了待ちであることが分かる。
cancel-in-progress: trueの場合
次にcancel-in-progress: falseの場合で動かしてみる。同時に2回workflowを手動実行する。
するとこんな感じで1つ目のworkflowがキャンセルされて、2つ目のworkflowが実行される。
1つ目のworkflowの中を見てみるとこんな表示になっている。
“Canceling since a higher priority waiting request for ‘Concurrency Test Workflow-refs/heads/main’ exists “と表示され、2つめのworkflowによってキャンセルされたことが記載されている。
おわりに
今回はGitHub Actionsのcuncurrencyを試してみた。これにより、CDの同時実行によるエラーを回避することができそう。また、workflowを動作させるランナーのリソースを節約したい時にも使えそうだった。