Shimpei Wakida's Blog

日々の学びをゆるりと.

Sprocketsのキャッシュが悪さしてSprockets::FileNotFound エラーが出てハマった

なぜそれが起こってしまったのかの詳細は分からないけど、忘れないうちに事実だけメモ。改めて情報整理できたら会社のテックブログに展開する。

環境

  • Ruby 2.7.6
  • Rails 6.1.5
  • capistrano 3.7.0

起こったこと

検証用の環境(以後、QA環境と呼ぶ)にて、特定のfeatureブランチをデプロイすると、scssファイルがないよーと怒られる。他のブランチでは起こらない。

could not find file: /home/{app_root}/releases/20221209000001/app/assets/stylesheets/hoge.scss

デプロイにはcapistranoを使用しています。

capistranoのデフォルト仕様で、デプロイするごとに releases/ 配下にリポジトリのソースコードをまるっと置きます。上記で言う20221209000001ディレクトリ内に、とあるデプロイ時のソースが入っています。

そして、最新のreleaseに、{app_root}/current とのシンボリックリンクが貼られます。

さらに、デプロイ時にcleanupというタスクが走り、最新の5つを残して他を削除します。 実際のcapistranoログはこんな感じ。

00:12 deploy:cleanup
      Keeping 5 of 6 deployed releases on {app名}
      01 rm -rf /home/{app_root}/releases/20221209000001

とりあえず、ないよーと怒られているreleasesを確認すると、すでにcapistranoのdeploy:cleanupタスクによって削除されており、存在していないではないか、、!

cd /home/{app_root}/releases/

ls -a
→  20221209000004 20221209000005 20221209000006 20221209000007 20221209000008 
# 20221209000001は存在しない

(※ releases配下のディレクトリ名は、実際にはタイムスタンプぽい命名になります。分かりやすくデプロイごとにインクリメントするテイにしています。)

すでに存在しないreleasesを参照するとはどういうことだ・・・!?

QA環境以外にも、同じインフラ構成の別の検証環境があるのでそちらにも問題のブランチをデプロイしてみます。別環境では問題なくブラウザからアクセスできる。これで、ソースコード起因ではなく、環境依存であることが確定しました。

キャッシュを疑う

詳しい仕組みは知りませんが、「このブランチではこのreleasesを見に行くよ」みたいなキャッシュが残ってるのかな?という仮説から、home/{app_root} ディレクトリ内で、存在しないreleaseディレクトリ名20221209000001の文字列をファイル内に含むファイルを検索かけてみる。

cd home/{app_root}

grep 20221209000001 -rl .
→
./shared/log/qa.log
./shared/tmp/cache/bootsnap/load-path-cache
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx
./shared/tmp/cache/bootsnap/compile-cache-iseq/xx/xxxxxxxxxxxxxx

(他にも ./shared/tmp/cache/bootsnap/compile-cache-iseq 配下のファイルがたくさん。この辺で出力を停止してしまった)

なんかいっぱい出てきた!!!

一番上の ./shared/log/qa.log はアプリのログなので無視。

それ以降は ./shared/tmp/cache/ という、明らかにキャッシュと思われるディレクトリにいる。

bootsnap

bootsnap とやらを調べてみる。

github.com

何やら、キャッシュによってrailsの起動時間を短くしてくれるらしい。よし、とりあえず深くは考えずキャッシュ消しちゃおう!

cd ./shared/tmp/cache/bootsnap/
rm load-path-cache
rm -r compile-cache-iseq
rm -r compile-cache-yaml

ちなみに、compile-cache-iseqcompile-cache-yamlのディレクトリ削除、めっちゃ時間かかりました(体感では5分以上)。

bootsnapのキャッシュを消したので、問題のfeatureブランチのデプロイ再チャレンジ!

could not find file: /home/{app_root}/releases/20221209000001/app/assets/stylesheets/hoge.scss

同じエラー😱😱😱

Sprockets

他にもキャッシュはないかとshared/tmp/cacheディレクトリ内を探すと、なんかいました。

cd  /home/{app_root}

ls -a 
→ bootsnap assets

assets 配下には、こんなやつがいました

shared/tmp/cache/assets/sprockets/v3.0

Sprocketsを調べてみる

railsguides.jp

アセットパイプラインの技術の根幹っぽいことと、キャッシュしていることは分かった。よし、とりあえず深くは考えずキャッシュ消しちゃおう!(2回目)

rm -r shared/tmp/cache/assets/sprockets/v3.0/* #v3.0配下にたくさんキャッシュがある

キャッシュを消したので、再チャレンジ!

、、、いけた!!!!!!

というわけで、今回は Sprocketsのキャッシュを消すことでうまくいきましたとさ。

補足

ちなみに、Sprockets キャッシュ削除後のデプロイでrails起動時、ブラウザでアクセスすると504エラーになりました。15分ほど放置していたら勝手にrails起動して復活。キャッシュの偉大さを身をもって感じました。

参考