`Rails.cache.clear` で FileStore のキャッシュが削除されなかった話

Published at: 2021/09/11

問題

capistrano でのデプロイの度に、 Rails.cache.clear を実行していたのだけれども、ActiveSupport::Cache::FileStore のファイルが 削除されていないことがあったりしたので、その原因を調査した際の備忘録。

原因

def clear(options = nil)
  root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
  FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
rescue Errno::ENOENT, Errno::ENOTEMPTY
end

(出典: https://github.com/rails/rails/blob/f1a684ce9964f335072a3b2e8cb0b483e16056cb/activesupport/lib/active_support/cache/file_store.rb#L34-L38 )

ここにあるように、 ActiveSupport::Cache::FileStore.clear メソッドは、 Errno::ENOENTErrno::ENOTEMPTY の例外が発生した場合には、しれっとそれを握り潰して正常終了する。

さらには、この FileUtils.rm_r のコマンドは、これを実行している最中にそのディレクトリの中にファイルを作成したりしていると、 Errono::ENOTEMPTY が発生してしまう。

自分の場合だと、このキャッシュクリアのコマンドを、 capistrano のデプロイ直後に実行していた結果、 puma が新しいバージョンのアプリで起動しようとして、 bootsnap のキャッシュ(FileStore のデフォルトのキャッシュパスと同じ所tmp/cacheに生成される)をもりもり生成するタイミングと、Rails.cache.clear のタイミングが被ってしまい、結果 Errono::ENOTEMPTY が発生しそこでキャッシュの削除がアボートして正常終了する、という挙動になっていた。

対策

Rails.cache.clear は、 puma の restart など、アプリの立ち上がり処理のタイミングを避けて実行する。

tags: rails