見出し画像

Rspec on CircleCiの待ち遅くない?だるくない?なんとかしたくない?

こんにちは、taskeyの田代です。
21年始まってしまいましたが、20年でやったことで書いていないことがあったので、一足遅いですが、こちらに残して行きたいと思います。

弊社サービス

こちらのサービスではサーバーサイド技術としてRuby on Railsを採用しております。

多くの場合、Railsを採用した現場では、Ci上でRspecやRuboCopを回して、合格した場合のみmaster(main)ブランチへのmergeが可能、という開発フローを用いていることが多いと思います。

Rspec on Ciではテスト数が多くなるに比例して速度が落ちていくという問題があります。「Rspec 遅い」で検索するととても多くの記事がヒットするのが裏付けとなっています。また、ランダムに落ちるというRspecも厄介ですね。

先に結果から書かせていただきますと、いくつかの技術と札束を用いた結果30分 => 5分 の速度改善を達成しました。勿論ランダムに落ちるRspec問題もクリアしております。

スクリーンショット 2020-12-30 10.46.18

(完成イメージ)

 並列数を増やすことによりこれ以上遅くなることを防げます。
※ 逆にこの5分には削りにくいsetupの時間もあるためこれ以上の速度改善は別レイヤーでのチューニングになります。

問題点まとめ

①: Rspecが純粋に遅い
②: ランダムで落ちるRspecが存在しているため、落ちる度に全てのテストを実行しなければならない

アプローチ方法

問題①: Rspecが純粋に遅い
こちらのアプローチ方法で考えうる対応案は下記通りです。

 - 特に遅いRequest系のテストを捨てる
 - 遅くならない書き方を心がける
 - RspecをRubyの複数プロセスで実行する
 - RspecをCiの複数マシンで実行する

特に遅いRequest系のテストを捨てる
 => せっかく書かれている資産を捨てるのは勿体ないですし、今後RequestSpecを書けないのはリスクが高すぎます。却下。

遅くならない書き方を心がける
 => 検索した段階では、このような記事が多くヒットしたのですが、既存のテストを書き換えるコストを考えると現実的では有りません。勿論遅くならない書き方を個人スキルとして身につけておくというのはとても意味のあることだと思いますが、現リソースの配分を考えた上で今回は却下です。

RspecをRubyの複数プロセスで実行する
 => 実行順に依存したテストがある場合に落ちやすくなってしまいますが、それ以外の点では良さそうです。

RspecをCiの複数マシンで実行する
 => こちらも、マシン上でのテストの割り振り方をしっかりと考えられたら良さそうなアプローチです。Rubyの複数プロセスでの実行で十分な気もしますが、1マシンのメモリ、CPU数も上限があるので、拡張性を高めるためにも並行で採用した方が良さそうです


問題②: ランダムで落ちるRspecが存在しているため、落ちる度に全てのテストを実行しなければならない
こちらに関しては各テストをRetry可能にするのが良さそうです。他にはなにも思いつきませんでした。

採用技術

RspecをRubyの複数プロセスで実行する

 - parallel_tests

RspecをCiの複数マシンで実行する

 - CircleCi Parallelism
 - rspec_junit_formatter(gem)

各テストをRetry可能にする

 - rspec-retry(gem)

これらをうまく組み合わせるとこうなります👏👏

スクリーンショット 2020-12-30 10.46.18

参考までにテスト実行部分のymlを安直に貼っておきます。
あとは公式のUsageを読めば、なんとなく出来るはずです。

# Database setup
- run: bundle exec rake parallel:create[$PARALLEL_TESTS_CONCURRENCY]
- run: bundle exec rake db:migrate
- run: bundle exec rake parallel:prepare[$PARALLEL_TESTS_CONCURRENCY]
# Run RSpec
- run: |
mkdir -p /tmp/rspec
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)"
bundle exec parallel_rspec -n $PARALLEL_TESTS_CONCURRENCY -- $TEST_FILES
- store_test_results: 
path: /tmp/rspec
- store_artifacts:
path: /tmp/rspec

終わりに

上記構成を採用したことにより、実際弊社ではテスト待ち時間が激減しました。

また、影響範囲調査等でtestを落としながら確認したい場合もCiで回したほうがlocalより早い状態になった為、開発速度も上がっております。

今後テスト数増加により再度チューニングが必要になる場合もありそうですが、そのときは愚直にマシンを1台追加するだけです。楽。
CircleCiのマシン並列化に関しては課金制ですのでそこだけ注意してください。

Rspec遅い問題に関してはどの現場でも悩んで独自に解決していると思います。あくまで一例として参考にしてください。
逆にこうするともっと良いよって言う構成がありましたら、是非ご教授頂けましたら幸いです。

募集

弊社正直、エンジニアが足りてません!!!

Serverエンジニアに関して、下記現状です!!!
ご興味有る方是非ご連絡くださいー!!!

アピールポイント

・ Spec整備済み
・ OpenAPI 整備済み
・ 機能開発毎にエンジニアで設計や命名を話し合う風習あり
・ データマート(BigQuery)整備済み
・ Deployフロー整備済み
・ 負債に対しての定期的なMTGと、それを解像度高く分解して実行できる環境
・ ECS on Fargate、Aurora Auto Scaling とモダンなインフラを採用
・ データ分析、SRE、フロントエンド(React)、リコメンドエンジン等の幅の広いスキルの拡張が可能

現状の課題

・ 現状がRails5系、Ruby2.5系と、最新のバージョンへの追従が遅れている
=> 直近でVersionUP予定あり
・ APIで返却するJSONが最適化されていない
=> JSON整備予定あり
・ JSONResponse返却のGetRequestに対してのCDN整備が整っていない
=> 長期的観点でCDN導入予定
・施策速度優先とエンジニア不足により技術的負債を解消し切れていない  => DX、開発効率を上げていくためにも必須

この記事が気に入ったらサポートをしてみませんか?