对于生成代价高昂的页面或操作,标准的Rails缓存方法会在其基础数据变得过时时使页面/操作无效。然后,当发生缓存未命中并生成页面时,请求该页面的下一个用户必须在那里坐N秒。如果N足够大,这将使该用户感到悲伤。当然,它只是一个用户,但如果失效频繁,我们可能会让很多悲伤的用户。
一种解决方案是,每当我使某些页面/操作无效时,还会触发新版本的页面/操作的呈现并将它们放入缓存中。我需要几个小时的编码来构建我需要的版本。
但当然其他人已经解决了这个问题?我环顾四周,找不到合适的宝石或答案。
谢谢!
答案 0 :(得分:0)
我认为昂贵的计算不是HTML页面的呈现,而是填充页面所需的查询和/或计算。
正如您所说,当它变得无效时,您应该触发此计算/查询,以便下次访问该页面时它立即可用。
你可以存储各种格式的数据:YAML,Marshal转储,JSON,CSV等。如果你走这条路,我会将它存储在像文件系统或你的数据库那样永久存在的地方,而不是Rails缓存,因为不假定Rails缓存总是包含您的数据。
答案 1 :(得分:0)
终于找到了问题和答案:
问:"Warm Up Cache" on deployment
答:https://stackoverflow.com/a/942774/593053
在此留下我的问题,以便其他人可以跟踪并学习 从我的痛苦。
也相关:Rails 3.2: Pre-render (bake) a new page cache immediately after expiry?
我的完整解决方案是采用以下约定:如果cache=regen
位于请求的URL中,则表示生成的页面应填充到缓存中。
对于我想要缓存的控制器,include CacheRegen
。 CacheRegen
导致控制器在cache = regen时不从缓存中读取,并且在存储到缓存中时不将cache = regen放入密钥中。
代码为:
module CacheRegen
def read_fragment(key, options = nil)
if /cache=regen/.match(key)
logger.info("forcing cache miss due to param cache=regen, key=#{key}")
return nil
end
super(key, options)
end
def write_fragment(key, content, options = nil)
unless key.sub!(/cache=regen/, '').nil?
key.sub!(/\?\&/, '?')
key.sub!(/\&\&/, '&')
key.sub!(/\?$/, '')
key.sub!(/\&$/, '')
logger.info("wrote page to cache with key #{key}")
end
super(key, content, options)
end
end
最后,我将以下代码放在new_pages.rake中:
require 'action_dispatch'
def get_url(sess, url)
uri = "http://YOURSITE.com/" + url + "cache=regen"
puts "retrieving " + uri
foo = sess.get(uri)
puts "got it. #{foo}, #{sess.response.body.length} bytes"
end
desc "If necessary, generate new versions of the most expensive pages"
task :new_pages => :environment do
puts "Updating pages..."
sess = ActionDispatch::Integration::Session.new(Rails.application)
["controller1", "controller2", "controller3"].each { |noun|
get_url(sess, noun + "?")
}
puts "done."
end
在我的环境中,我有deploy
任务,这取决于new_pages
任务。
那里有一些宝石会让所有这些变得更加自动化吗?
答案 2 :(得分:-1)
rails中缓存失效的典型解决方案是扫描程序。它是自动缓存失效的技术。 您可以阅读有关清扫工in this guide
的更多信息