🏃

キャッシュを利用してCircleCIのRuboCopを高速化する (35秒 -> 4秒)

2023/07/27に公開

はじめに

ローカル環境などでRuboCopを実行する際にはよしなにキャッシュが利用され、高速化が図られています。

一方で、CircleCI上ではそうはいきません。RuboCopのキャッシュディレクトリを設定し、設定したディレクトリをCircleCIの依存関係のキャッシュ[1]を用いて次回以降のジョブに使い回す必要があります。

https://circleci.com/docs/ja/caching/

そこで、以下をまとめました。

  • キャッシュの利用によってどの程度の改善が見込めるのか
  • キャッシュの設定方法

キャッシュの有無による実行時間の比較

先にまとめを貼ります。

キャッシュの有無 RuboCop (秒) キャッシュのリストア (秒) 合計 (秒)
無し 35 0 35
有り 4 1 5

キャッシュを利用しない場合

RuboCopの実行時間は35秒、全体の実行時間は54秒でした。

キャッシュを利用した場合

RuboCopの実行時間は4秒、全体の実行時間は22秒でした。
キャッシュのリストアに要する時間 (1秒) を加味しても、実行時間が1/7になっています。

設定

各種設定を以下にまとめます。

  • RuboCopの設定
  • CircleCIの設定

RuboCopの設定 (抜粋)

.rubocop.yml にキャッシュに関する設定[2]を記述します。

https://docs.rubocop.org/rubocop/usage/caching.html

以下は関連する部分のみ抜粋したものです。

.rubocop.yml
AllCops:
  UseCache: true # デフォルトはtrue
  CacheRootDirectory: tmp # デフォルトは$HOME/.cache/

CircleCIの設定

比較のために2通りのジョブを定義したものです。

rubocop-without-using-cache では、RuboCopのキャッシュを利用しないでrubocopを実行しています。一方で、rubocop-with-using-cache では次回以降にRuboCopのキャッシュを持ち越すための設定が追加されています。

差分がわかりやすいよう、rubocopの実行とキャッシュ周りの処理以外は setup-rubocop にまとめています。

.circleci/config.yml
version: 2.1

commands:
  setup-rubocop:
    steps:
      - checkout
      - run:
          name: Install RuboCop
          command: |
            gem install rubocop

jobs:
  rubocop-without-using-cache:
    docker:
      - image: cimg/ruby:3.0.6
    resource_class: xlarge
    steps:
      - setup-rubocop
      - run:
          name: Run RuboCop
          command: |
            rubocop

  rubocop-with-using-cache:
    docker:
      - image: cimg/ruby:3.0.6
    resource_class: xlarge
    steps:
      - setup-rubocop
      - restore_cache:
          keys:
            - rubocop-cache-{{ .Branch }}-{{ .Revision }}
            - rubocop-cache-{{ .Branch }}-
            - rubocop-cache-
      - run:
          name: Run RuboCop
          command: |
            rubocop
      - save_cache:
          key: rubocop-cache-{{ .Branch }}-{{ .Revision }}
          paths:
            - tmp/rubocop_cache
	    
workflows:
  ci_cd:
    jobs:
      - rubocop-without-using-cache
      - rubocop-with-using-cache

おわりに

ちょっとしたコード変更でも大きな改善が得られました。

RuboCopに限らず、ローカルと比べてCircleCI上では遅い事象に遭遇した際には、ローカルにキャッシュディレクトリが作られている可能性を疑うと良いかもしれません。

参考

https://circleci.com/docs/ja/caching/

https://docs.rubocop.org/rubocop/usage/caching.html

脚注
  1. CircleCI 依存関係のキャッシュ ↩︎

  2. RuboCop / Usage / Caching ↩︎

Discussion