Railsでオンメモリにキャッシュするとハマるので注意
Railsのフラグメントキャッシュでオンメモリを指定してたら、外部ミドルウェアを使うのと挙動が違ってハマったのでメモ。
開発環境デフォルトのオンメモリは準備が楽ですが、本番でDalliとか使ってると混乱するので統一しておきたいですね。
検証
恐らく最もよく使われると思われるRails.cache.fetchの結果をそれぞれ見てみます。
Dalli(Memcached)
設定値config.cache_store = :mem_cache_store
[1] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} Dalli::Server#connect localhost:11211 no cache => {:hoge=>"huga"} [2] pry(main)> @tmp[:foo] = 'bar' => "bar" [3] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} => {:hoge=>"huga"} [4] pry(main)> @tmp[:foo] = 'bar' => "bar" [5] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} => {:hoge=>"huga"}
on Memory
設定値config.cache_store = :memory_store
[1] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} no cache => {:hoge=>"huga"} [2] pry(main)> @tmp[:foo] = 'bar' => "bar" [3] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} => {:hoge=>"huga"} [4] pry(main)> @tmp[:foo] = 'bar' => "bar" [5] pry(main)> @tmp = Rails.cache.fetch('hoge'){puts 'no cache'; {hoge: 'huga'}} => {:hoge=>"huga", :foo=>"bar"}
このようにオンメモリではキャッシュされた値に、その後の変更が適応されています。
原因
恐らく、オンメモリだとrailsプロセスと同一のメモリ空間に保存されるため、ポインタのその後の変更も適応されているんだと思います。三回目の呼び出しまで適応されない理由はわかりませんが......(ドキュメントとかコードちゃんと読んだ人教えて!)
結論
あんまりオンメモリストア使うもんじゃないね。