parallelを利用してGitHub Actionsのstepを並列実行する
少し前に、GitHub Actionsのjobのstepにparallelが追加されました。 存在は知っていましたが、あんまりよくわかっていないので使ってみて理解を深めようと思います。
stepを並列実行をするには
従来、同一job内のstepを公式の構文で並列実行する仕組みはなく、matrixでjobを分割するか、shellの&などを利用する必要がありました。
matrixでは、1つのjob定義から値の組み合わせごとに複数のjob runが生成されます。
使い方は次のようなイメージです。(公式の例をそのまま引用)
jobs:
example_matrix:
strategy:
matrix:
version: [10, 12, 14]
steps:
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.version }}
この例では、同じjob定義からversionの値ごとに3つのjob runが生成され、それぞれでsetup-nodeが実行されます。
また、shellの&などの仕組みをうまく利用してバックグラウンドでタスク実行することにより並列に処理を実行すること自体は可能となっていましたが、このケースではバックグラウンド処理に関するログ管理を適切に行う必要がありました。
つまり、並列実行自体は可能なものの、シンプルに実現できる方法自体は用意されていませんでした。
そして、そこに対する回答として、parallelという仕組みが生まれました。 今回はその仕組みについて少し深ぼってみようという話になっています。
parallelという仕組み
parallel は、job内のstepを並列に実行するための仕組みです。
書き方は次のような感じで、とてもシンプルです。(公式の例をそのまま引用)
steps:
- uses: actions/checkout@v6
- parallel:
- name: Build frontend
run: npm run build:frontend
- name: Build backend
run: npm run build:backend
- name: Build docs
run: npm run build:docs
- name: Run tests after all builds complete
run: npm test
大前提として、parallelブロック内に定義した処理は、同一job、同一runner上で動きます。
挙動としては、parallelブロック内に記述した処理が全て完了したら、次のstepに移ります。
また、parallel内に定義したstepが1つでも失敗した場合は、parallel step自体が失敗となり、特にif: always()などを指定していない場合、次のstepは実行されないという動きを取ります。
利用用途ですが、上記例がわかりやすく、複数の独立したタスクを実行した上で次のステップを実行するようなシチュエーションがイメージしやすいと思います。
当然ですが、parallel内で定義したstepについては他のstepと同様別々のものとして扱われ、ログも特別な設定などなしに表示されます。
この辺りが&を駆使するパターンとの大きな差別化になっていそうです。
matrixとparallelの使い分け
ここまでで、GitHub Actionsには大きく分けてmatrixとparallelという2つの並列化の仕組みが存在するということを確認しました。
一方で、この2つの機能はどちらかがどちらかを完全に包含するようなものではないため、一定の使い分けが必要な仕組みとなっています。
まだ私自身、しっかりと活用したことがないので若干の誤りがあるかもしれませんが、パッと想像する感じ、次のような使い分けになりそうです。
- matrix
- CPU boundな処理が複数走るケース
- タスクをjobに水平分割して実行するmatrix方式に分がある
- runnerやOS、ランタイムのバージョンなどを変えて処理を実行したいケース
- CPU boundな処理が複数走るケース
- parallel
- 同じrunner上のセットアップ内容や作業ディレクトリを共有しつつ、独立した処理を複数実行したいケース
- 例えば、環境セットアップ後にlint、unit test、integration testをコマンドを変えて回すようなケース
- 同じrunner上のセットアップ内容や作業ディレクトリを共有しつつ、独立した処理を複数実行したいケース
まとめ
GitHub Actionsのstepを並列実行するための仕組みとしてparallelが実装されました。
パッと想像するだけでも既存のワークフロー内の処理をparallelを利用して置き換えられそうなパターンがいくつかありそうです。
matrixを利用するには過剰だが、&を利用するとログ周りの管理がめんどくさいというパターンに対する良い回答だと思いました。