全然使ったことがなかったのですが、ABテストやりたいなーというのがきっかけでredisを手元で触ってみました。
データ作成
# Product => Product(id: integer, name: string, published_at: datetime, created_at: datetime, updated_at: datetime) > 1.upto(10).each do |i| > Product.create(id: i, name: "product_#{i}", published_at: Time.zone.now) > end
コード
class ProductsController < ApplicationController def show @product = Product.find(params[:id]) fresh_when last_modified: @product.published_at, etag: @product end end
# products/show.html.erb <h1> product info</h1> <p><%= @product.id %></p> <p><%= @product.name %></p>
ログ
初回
app/controllers/products_controller.rb:4:in `show' Started GET "/products/1" for ::1 at 2020-03-01 14:19:10 +0900 (0.3ms) SELECT sqlite_version(*) Processing by ProductsController#show as HTML Parameters: {"id"=>"1"} Product Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/products_controller.rb:3:in `show' Rendering products/show.html.erb within layouts/application Rendered products/show.html.erb within layouts/application (Duration: 1.4ms | Allocations: 121) [Webpacker] Compiling... [Webpacker] Compiled all packs in /Users/keiko/workspace/practice/ab-test/public/packs [Webpacker] Hash: 32e57f147dbdcbbf0c82 Version: webpack 4.41.6 Time: 21457ms Built at: 2020-03-01 14:19:49 Asset Size Chunks Chunk Names js/application-bbe9c4a129ab949e0636.js 124 KiB application [emitted] [immutable] application js/application-bbe9c4a129ab949e0636.js.map 139 KiB application [emitted] [dev] application manifest.json 364 bytes [emitted] Entrypoint application = js/application-bbe9c4a129ab949e0636.js js/application-bbe9c4a129ab949e0636.js.map [./app/javascript/channels sync recursive _channel\.js$] ./app/javascript/channels sync _channel\.js$ 160 bytes {application} [built] [./app/javascript/channels/index.js] 211 bytes {application} [built] [./app/javascript/packs/application.js] 749 bytes {application} [built] [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 552 bytes {application} [built] + 3 hidden modules Completed 200 OK inViews: 39167.4ms | ActiveRecord: 3.2ms | Allocations: 24240)
webpackerのコンパイルが走ってるので結構時間がかかっています。
リロード
Started GET "/products/1" for ::1 at 2020-03-01 14:24:07 +0900 Processing by ProductsController#show as HTML Parameters: {"id"=>"1"} Product Load (7.2ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/products_controller.rb:3:in `show' Completed 304 Not Modified in 605ms (ActiveRecord: 7.2ms | Allocations: 1073)
Completed 304 Not Modified
と出ています。
データを更新して再表示
> Product.find(1).update(name: 'upadted_name') (1.5ms) SELECT sqlite_version(*) Product Load (0.3ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] (0.2ms) begin transaction Product Update (1.2ms) UPDATE "products" SET "name" = ?, "updated_at" = ? WHERE "products"."id" = ? [["name", "upadted_name"], ["updated_at", "2020-03-01 05:25:32.072118"], ["id", 1]] (3.0ms) commit transaction => true
Started GET "/products/1" for ::1 at 2020-03-01 14:26:05 +0900 Processing by ProductsController#show as HTML Parameters: {"id"=>"1"} Product Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] ↳ app/controllers/products_controller.rb:3:in `show' Rendering products/show.html.erb within layouts/application Rendered products/show.html.erb within layouts/application (Duration: 1.0ms | Allocations: 9) [Webpacker] Everything's up-to-date. Nothing to do Completed 200 OK in 1035ms (Views: 1024.1ms | ActiveRecord: 0.5ms | Allocations: 4675)
Completed 200 OK
となっています。
fresh_when
メソッド
ActionController::ConditionalGet
railsのActionControllerにあるメソッドです。
etag
rails guideによると”一致”の捉え方が変わるようです。
弱いETagでは、レスポンスのbodyが微妙に異なっている場合にも同じETagを与えることで、事実上同じレスポンスとして扱えるようになります。
(中略)
強いETagは、弱いETagと異なり、レスポンスがバイトレベルで完全一致することが求められます。巨大な動画やPDFファイル内でRangeリクエストを実行する場合に便利です。
キャッシュをproductionで使う際には「レスポンスが早くても情報が古くては事故になりかねないので、キャッシュを使いこなせないなら使わないほうがいい」ということをアドバイス頂いたことがあるのですが、etag
の指定はこのアドバイスと関連しそうです。
感想
ガイドを見ながら使ってみましたが、この記事を書いていて「こうらしい」「ということだそうです」というふうに、自分で断言できない事項がとても多いこともあり、どうやらredisそのものの理解が必要そうです。
あと、私がやりたいのはキャッシュではなくてABテストなので、その角度からも近々やってみます。
全然わかってないのでドットインストールあたりで基本をおさえて行こうと思います。
追記) ドットインストールのredis入門やったのですが、短時間で世界観がざっとおさえられてよかったです。さらっとした部分だけだったので、詳しいredisの操作は公式ドキュメントみながら回数こなしてなれていけたらいいなあ。