こんにちは。 .gitlab-ci.yml を書くのが好きな河内です。
社内では GitLab をホスティングして使っています。 GitLab の機能追加速度はすごいですね。 毎月22日にリリースされることになっており、毎回それなりに機能追加されています。
さて、11月22日にリリースされた GitLab 11.5 では CI ジョブの設定に parallel
属性が追加されました。
parallel
属性を指定すると、その数のジョブが並列に実行されます。
各ジョブには CI_NODE_TOTAL
(並列ジョブの総数)と CI_NODE_INDEX
(自身のジョブのインデックス)が設定されます。
例えば parallel: 4
と指定した場合、4 つのジョブが並列実行されます。
それら全てのジョブで CI_NODE_TOTAL
環境変数は 4 に設定されます。
CI_NODE_INDEX
は各ジョブで 1 から 4 までの数字が設定されます。
各ジョブはこれら2つの環境変数を参照して、作業を分担することが想定されています。
ここでは sbt を使って Scala プログラムをテストするときに、作業を分担する方法を紹介します。
testOptions
に Tests.Filter
を指定すると、条件を満たしたテストのみを実行できるので、これを利用します。
build.sbt
に次のように記述します。
import scala.util.Try testOptions in Test ++= (for { indexString <- sys.env.get("CI_NODE_INDEX") index <- Try(indexString.toInt).toOption totalString <- sys.env.get("CI_NODE_TOTAL") total <- Try(totalString.toInt).toOption if index >= 1 && total >= 1 && index <= total } yield Tests.Filter(testCls => math.abs(testCls.hashCode % total) == index - 1)).toSeq
Tests.Filter
は、テストクラス名を受け取ってテスト対象とするか否かの関数 (String => Boolean
) を受け取ります。
ここでは雑にテストクラス名の hashCode を CI_NODE_TOTAL
で割って、余りが CI_NODE_INDEX
となるテストのみを実行対象としています。
これだけで、テストの分担は完了です。 sbt 便利ですね!
あとは .gitlab-ci.yml
のジョブ設定で parallel: n
と設定すれば n 並列でテストが実行されます。
sbt 起動やコンパイルなどのオーバヘッドがかかるため、単純に n 倍速にはなりませんが、テストの時間だけを取り出して考えると n 倍速が期待できます。
テストが長くて困っている人は是非お試しあれ。