1

我的 Rails 3 应用程序生成的页面将在指定的时间段内发生变化,然后在其剩余生命周期内保持静态(无变化)(想想:体育记分牌)

这似乎是全页缓存的绝佳机会,因此我选择了 Rack::Cache,使用响应的 Last-Modified 部分来指示缓存何时无效。

缓存工作得很好——太好了。似乎即使 Last-Modified 字段更新的日期/时间晚于请求的 If-Modified-Since 字段并且响应生成状态 200(而不是 304),浏览器仍会加载缓存在服务器上的页面版本。

这是我在服务器调试日志中看到的:

App 16638 stdout: Started GET "/games/2014/2/10" for xx.xx.xx.xxx at 2014-02-11 04:04:11 +0000
App 16638 stdout: Processing by GamesController#index as HTML
App 16638 stdout:   Parameters: {"year"=>"2014", "month"=>"2", "day"=>"10"}
App 16638 stdout:   Game Load (2.8ms)  SELECT "games".* FROM "games" WHERE "games"."date" = '2014-02-10'
App 16638 stdout:   Game Load (2.8ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 877 LIMIT 1
App 16638 stdout:   Team Load (1.3ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 10 LIMIT 1
App 16638 stdout:   Team Load (0.7ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 23 LIMIT 1
App 16638 stdout:   Game Load (4.2ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 875 LIMIT 1
App 16638 stdout:   Team Load (0.6ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 17 LIMIT 1
App 16638 stdout:   Team Load (5.4ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 2 LIMIT 1
App 16638 stdout:   Game Load (7.0ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 874 LIMIT 1
App 16638 stdout:   Team Load (0.7ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 9 LIMIT 1
App 16638 stdout:   Team Load (7.9ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 27 LIMIT 1
App 16638 stdout:   Game Load (0.7ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 876 LIMIT 1
App 16638 stdout:   Team Load (0.4ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 18 LIMIT 1
App 16638 stdout:   Team Load (0.4ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 11 LIMIT 1
App 16638 stdout:   Game Load (0.6ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 873 LIMIT 1
App 16638 stdout:   Team Load (4.0ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 12 LIMIT 1
App 16638 stdout:   Team Load (0.6ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 8 LIMIT 1
App 16638 stdout:   Game Load (5.4ms)  SELECT "games".* FROM "games" WHERE "games"."id" = 872 LIMIT 1
App 16638 stdout:   Team Load (0.6ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 28 LIMIT 1
App 16638 stdout:   Team Load (3.9ms)  SELECT "teams".* FROM "teams" WHERE "teams"."id" = 19 LIMIT 1
App 16638 stdout: Latest game: 2014-02-11 03:44:50 UTC
App 16638 stdout: Cache read: views/xxxx/games/2014/2/10
App 16638 stdout: Dalli::Server#connect 127.0.0.1:11211
App 16638 stdout: Read fragment views/xxxxx/games/2014/2/10 2.6ms
App 16638 stdout: Completed 200 OK in 618.2ms (ActiveRecord: 128.8ms)
App 15100 stderr: cache: [GET /games/2014/2/10] stale, invalid, store
App 16638 stdout: Started GET "/assets/bootstrap.css" for 66.55.150.181 at 2014-02-11 04:04:12 +0000
App 16638 stdout: Served asset /bootstrap.css - 304 Not Modified (12ms)
App 15100 stderr: cache: [GET /assets/bootstrap.css] stale, valid, store
App 15100 stderr: cache: [GET /assets/application-85cd667c6ae785b5d80f452fe6ad811e.js] fresh
App 15100 stderr: cache: [GET /assets/application-50dd9f33494a58a079e7417a68763e42.css] fresh

这是一个示例请求/响应(请参阅 200 状态):

    Request URL:http://xxxxxxx.com/games/2014/2/10
Request Method:GET
Status Code:200 OK
Request Headersview source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Cookie:_gamestory_app_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJWIwYjAwNWQ3NTBmYTk4YjQ0YWRjYjEwMWQ5Y2ZjYTA2BjsAVEkiEF9jcx3JmX3Rva2VuBjsARkkiMXdKNWZZUWFhZDVHN3hEeEJjaWxYclp1NmN4OGUrSkI4VzJ2eXdWOUsrc1E9BjsARg%3D%3D--6f99b71bca632560c069c371fdb6a4477a26dfa3
Host:xxxxxxxxx.com
If-Modified-Since:Tue, 11 Feb 2014 03:43:06 GMT
If-None-Match:"e282d8be52fbe437d3c2d3908288100d"
User-Agent:Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17
Response Headersview source
Age:0
Cache-Control:public
Connection:keep-alive
Content-Length:10411
Content-Type:text/html; charset=utf-8
Date:Tue, 11 Feb 2014 04:04:11 GMT

ETag:"d6d4c1f573a56353e0abbe14de76e306"
Last-Modified:Tue, 11 Feb 2014 03:44:50 GMT
Server:nginx/1.4.4 + Phusion Passenger 4.0.29
Status:200 OK
X-Content-Digest:7b2caeed19cc4674669f4c386271054427342b5e
X-Powered-By:Phusion Passenger 4.0.29
X-Rack-Cache:stale, invalid, store
X-Request-Id:c19584efff9941bf5c456cb68d85b192
X-Runtime:0.661659
X-UA-Compatible:IE=Edge,chrome=1

在相关控制器中,我对给定操作使用 before_filter,在该过滤器中,我在页面上最后更新的对象上使用 fresh_when。这似乎在响应中生成了正确的日期/时间,但我包含了任何可能错误的代码(为简洁起见,我删除了 show 操作):

class GamesController < ApplicationController
  helper ApplicationHelper
  before_filter :set_index_cache_headers, :only => [:index]
  caches_action :index

  def set_index_cache_headers
    @date = Date.today

    if params[:year] && params[:month] && params[:day]
      @date = Date.new(params[:year].to_i, params[:month].to_i, params[:day].to_i)
    else
      most_recent_game = Game.where(status: [:final, :in_progress]).order("date DESC").first

      if most_recent_game != nil
        @date = most_recent_game.date
      end
    end

    @games = Game.where(:date => @date).compact

    @game_infos = []

    @games.each do |g|
      @game_infos.push GameInfo.new(g.id)
    end

    @latest_game = @games.max_by{|g| g.updated_at}

    Rails.logger.debug "Latest game: #{@latest_game.updated_at}"
    fresh_when(@latest_game, public: true)
  end

  def index

  end
end
4

2 回答 2

1

如果我了解您正在尝试什么,我相信您将需要设置 expires_in(最好在 after_filter 中,这样您就不会缓存具有 500 状态的响应)。现在看起来机架缓存正在无限期地缓存您的页面(或任何默认值),并且您的请求永远不会到达 rails 后端。Rack-cache 认为您的缓存是“新鲜的”,因此不会费心返回重新生成页面。这篇文章很好地解释了它是如何工作的:

http://blog.tonycode.com/archives/418

只有当您真正通过机架缓存中间件并到达您的 Rails 层时,才会调用“fresh_when”。如果这样做,它将返回 304,除非您更新了记录(@latest_game)。

希望有帮助,祝你好运!缓存失效是一种痛苦。

于 2014-02-12T22:03:20.517 回答
0

事实证明,控制器中的这一行:

caches_action :index

是罪魁祸首。我的意图是只使用 Rack::Cache HTTP 缓存,但这一行激活了 Rails 动作缓存,这不是我的意图。让两个缓存系统一起运行是导致问题的原因。删除此行,解决了问题。

于 2014-02-17T20:21:00.127 回答