LoginSignup
9
4

More than 5 years have passed since last update.

drone.io(OSS版)で並列テストを実行してビルド時間を削減する

Posted at

プロダクトが成長してテストコードの規模が大きくなってくるとテスト実行時間も延びてきます。成長は嬉しいけど、ビルド時間が延びるのは嬉しくないです。そこでテストを並列で実行できるようにdrone.ioを設定してみます。

なお、CircleCI2.0での並列テストの方法は同僚が試してくれました。以下の記事を参考にしてください。

マトリックスビルド

drone.ioにはマトリックスビルドという機能があります。これを使うことで複数のworker(Dockerコンテナ)を並列で実行させられます。設定は簡単です。

.drone.yml


pipeline:
  build:
    image: hoge/piyo
  commands:
    - RAILS_ENV=test bundle exec rspec ${TESTFOLDER}

matrix:
  TESTFOLDER:
    - spec/models
    - spec/requests

これだけで2つのworkerが立ち上がり、それぞれで spec/modelsspec/requests のテストを実行してくれます。やったね🎉 でも実際これは上手くいきません。なぜなら最も実行時間のかかるリクエストテストが1つのworkerに集中してしまっているからです。片方はすぐ終わるのに、結局全体の実行時間はあまり改善されません(CircleCIなら勝手にランダムにしてくれるんだけどな…)。

テストコードファイルを分散する

というわけで、テストコードのファイルを分散するようにします。雑に書いたスクリプト例です。

require 'fileutils'
require 'pathname'

class RandomDistSpec

  def initialize
    FileUtils.rm_rf("matrix_specs")
    @worker_num = 4
  end

  def copy_ruby_spec
    specs = Dir.glob("spec/**/*_spec.rb").shuffle
    copy specs
  end

  private
  def copy specs
    slice_num = (specs.size / @worker_num).ceil

    1.upto(@worker_num) do |i|
      FileUtils.mkdir_p("matrix_specs/#{i}") unless FileTest.exist?("matrix_specs/#{i}")

      files = specs.slice!(0, slice_num)
      files.each do |file|
        dir = Pathname(file).dirname.to_s
        FileUtils.mkdir_p "matrix_specs/#{i}/#{dir}"
        FileUtils.cp file, "matrix_specs/#{i}/#{file}"
      end
    end
  end
end

spec = RandomDistSpec.new
spec.copy_ruby_spec

こうすることで、 /matrix_specs/n ディレクトリにランダムにファイルが配置されます。合わせて .drone.yml も修正します。

matrix:
  TESTFOLDER:
    - matrix_specs/1
    - matrix_specs/2

これでテスト実行時間が無事削減できました。

CIは非常に便利ですが、CIでのビルド時間が長いと改善サイクルが上手く回せません。待ち時間が発生し、集中力を取り戻すのにコストがかかります。なのでCIは積極的に改善をしていくべきところだなぁと思いました。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4