勝手にクリア。
Railsのキャッシュは基本的に、次のような挙動をする。
- ページがリクエストされた際にキャッシュが生成され、保存される
- データベースが更新されると、あらかじめ定義されていたSweeperが動いてキャッシュが破棄される
この仕組みのキモはSweeperで、DBの更新と連動してキャッシュがクリアされるので常にDBの最新データがページに載る。反面、Sweeperを書き間違うとキャッシュがクリアされず、ページ上の値とDB上の値が食い違って困ったことになる。
このキャッシュ破棄を、自動で出来ないだろうか?
効率を度外視すれば、次のような手法で実現できるんじゃないかと考えた。
ページがリクエストされた際
- アクション中でDBから取得された全レコードのテーブル名とIDを控える(a)
- 同じアクション中で、今回新たに生成されたキャッシュのファイル名を全て控える(b)
- (a)のそれぞれに対して、(b)のファイル名を結びつけて保存(c)
- この際、以前に保存された値があったらマージする
DBが更新された際
- 更新されたレコードのテーブル名とIDから、以前に保存されたキャッシュファイル名を(c)より取得
- 得られた名前のキャッシュを全て破棄
具体的には次のような流れ。
/foo/bar/1がリクエストされた
foosのID1、barsのID1, 2, 3がfindされる
a=["foos_1", "bars_1", "bars_2", "bars_3"]
Viewが解釈されてページが生成され、送り返される。同時に次のキャッシュが生成されて保存される。
b=["/foo/bar/1.html", "foo_1.cache", "bar_1.cache", "bar_2.cache", "bar_2.cache"]
aにbを結びつけて保存。
c={"foos_1" => b, "bars_1" => b, "bars_2" => b, "bars_3" => b}
foosのID1が更新された
c["foos_1"]の値に格納されたファイル名のキャッシュをクリア
c["foos_1"].each do |value| #valueを使ってexpire_* end
クリアする必要のないキャッシュまで破棄する場合が出てくるから、効率は当然ちゃんとSweeperを書くより悪くなるし、IDとキャッシュファイル名を結びつけて保存する際のオーバーヘッドも問題になるだろう。と言っても、試してみる価値はあるような気がする。プラグイン書けば実現できるかな?