Open8

github actions の npm のキャッシュについて

兎羽卯崎兎羽卯崎

やりたい

  • PRが上がったら自動でeslintを走らせたい
  • node
  • 将来的にtestとかを並列で走らせたい
  • npm packageはキャッシュしておきたい

方針

  • setupのjobsでnpmをinstallしてキャッシュしておく
  • 並列実行したいjobでsetupでinstallしたpackageをつかいた(かった)
  • キャッシュしてるので npm ciにした
兎羽卯崎兎羽卯崎

actions/setup-node@v3cache: npm するとキャッシュされるって書いてあるけど、
されないぞ、って言ってる人も結構いる、どっちやねん。

あと、各job間でinstallしたnpm packageは共有できない

兎羽卯崎兎羽卯崎

会社のプロジェクトだと各job間でnpm packageが共有できててなんでやねんってなったけど、setup job で、npm installしたあとにnode_modules フォルダをキャッシュして、ほかのjobでそのフォルダを展開していたからっぽい?

actions/setup-node@v3cache: npmの例だと npm ciしている
この設定だと ~/.npm をキャッシュする?
で、npm cinode_modulesがあった場合は削除して、~/.npmをまず確認してあればそこからinstallして、なければ落としてくる挙動っぽい?

ので、各jobごとに最初に npm ci すればちゃんとキャッシュをつかってpackageがinstallされる・・・
ということっぽい?

https://dev.classmethod.jp/articles/cicd-npm-ci-cache/

兎羽卯崎兎羽卯崎

actions/setup-node@v3cache: npm だと各job間で必ずnpm ciをやらないといけないのでその分時間がかかる、そしてgithub actionsは時間課金なので、ちょっとした時間が積み重なってかなりの額になる。

actions/cache@v3node_modulesをキャッシュしておけば、npm installのコマンド自体を飛ばせるし、そのあとのjobはそのキャッシュを展開するだけで、npm installが不要なので、実行時間自体はだいぶ短くなってるっぽい。
ただし、npm installpackage-lock.jsonに必ずしも沿うわけではないので、local環境とciの環境でバージョンが異なってなにか問題が起きる可能性があるかもしれない。

でも正直会社で1年以上、この設定で業務をしているが、問題が起こったことがない。

とりあえずcache: npmnpm ci
お金の問題があるならnode_modulesをキャッシュする方向が良さそうかなぁ?

兎羽卯崎兎羽卯崎

actions/cache@v3node_modulesをキャッシュした際の利点は npm ci でキャッシュから再インストールするのとくらべて早いこと。

hashFiles('**/package-lock.json') 完全一致で node_modules のキャッシュを作っておいて、ヒットすればそれを展開するだけ、ヒットしなければ npm cipackage-lock.json にそってインストールしてキャッシュするようにすれば早そう

      # node_modules がキャッシュされていれば展開する
      - name: Cache node modules
        id: cache-npm
        uses: actions/cache@v3
        env:
          cache-name: cache-node-modules
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
          restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}

      # node_modules がキャッシュされてなければ npm ci
      - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
        name: node
        uses: actions/setup-node@v3
        with:
          node-version: '16'

      - if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
        name: npm install
        run: npm ci

      - name: なんかやりたい処理
        run: npm run hoge

実際やってみたら一番はやくなった。

兎羽卯崎兎羽卯崎

node_modules をキャッシュしたらだめなのは、npm ciだとnode_modulesが一回削除される、npm i だと依存パッケージがおかしくなる可能性があるから(ほかにも理由あるのかな?)

このコードだとキャッシュがない = package-lock.jsonが変わっている(or 初回)ことになるのでnpm ciで新しく作られていいし、キャッシュがあるなら npm cinpm i も走らないので依存関係は正しい状態の node_modules が展開されるので問題は起こらない気がした。

問題があるとしたら、jobが多いと、同じ処理が何回も出てきて微妙ってところなのかな?