Rails:定时任务如何预热缓存?

8

我正在使用以下代码使用memcached缓存加载缓慢的页面:

caches_action :complex_report, :expires_in => 1.day

控制器操作受Devise身份验证保护。

当前页面在用户第一次请求时被缓存。随后的请求将从缓存中获取。

问题在于,初始请求需要20-30秒才能加载完毕。是否可以通过定期任务提前填充缓存?

非常感谢任何建议。


页面渲染是否需要用户?也就是说,当前用户(current_user)是否需要可用才能使页面正常渲染? - mnelson
是的,报告中使用了 current_user - gjb
4个回答

6

以下是基于之前的cron解决方案的扩展,它使用curl的存储cookie功能,以便您可以在一步中进行身份验证,然后在下一步中再次使用cookie作为已验证的用户。因此,如果您将这些行放入名为“prepare_cache.sh”的脚本中

rm /tmp/cookiejar
curl --request POST -d "login=<username>" -d "password=<password>" -c /tmp/cookiejar http://yourwebpages.url/login
curl --request GET -b -c /tmp/cookiejar http://yourwebpages.url/page_to_cache
rm /tmp/cookiejar

将登录和密码参数替换为与您的登录表单中使用的变量匹配的参数,显然还需要调用相应的URL。在此之前,我将删除cookiejar以确保没有文件存在,最后再删除它以确保没有漂浮的cookie可以访问不应该访问的级别。

然后,您可以使用cron作业调用此脚本:

*/15 * * * * /home/myname/prepare_cache.sh > /dev/null 2>&1

希望这样做能够起作用。当我尝试时,似乎对我有效。


那个完美地运行了,谢谢。一个整洁的解决方案,不需要对现有代码进行任何修改。 - gjb

4

看一下这个宝石:

https://github.com/tommyh/preheat

这个宝石是用于预热你的 Rails.cache。

从文档中可以得知: 这将在主页上“预热”所有的 Rails.cache.fetch 调用。就这么简单!

    #app/models/product.rb
    def slow_method
      Rails.cache.fetch("product-slow-method-#{self.id}") do
        sleep 15
        Time.now
      end
    end

    #lib/tasks/preheat.rake
    namespace :preheat do
      desc "Preheat product caches"
      task (:products => :environment) do
        Preheat.it do
          Product.all.each do |product|
            app.get(app.products_path(product)) #or you could just call product.slow_method directly, whatever makes more sense
          end
        end
      end
    end

    #crontab -e
    0 * * * * /path/to/rake preheat:products RAILS_ENV=production 2>&1 >> #{Rails.root}/log/preheat.log &

4
如果运行报告和收集结果是耗时的过程,您可以使用Rails.cache.writeRails.cache.read缓存这些结果(代替或与操作缓存一起)。然后,由于无需担心身份验证或向服务器发出请求,因此从cron作业运行查询并缓存结果的操作将更加简单。

我喜欢这种方法 - 缓存出现在报告中的数据,而不是报告本身,然后预热该缓存。如果经常访问报告,甚至值得同时进行两者,但只需预热后端数据的缓存即可。 - Paul Russell
谢谢您的建议。这肯定会有所帮助,通过缓存复杂查询的结果,但是视图中还存在一些条件格式设置(不同值的不同表格单元格样式)。因此,我更喜欢缓存页面而不仅仅是数据。 - gjb

3

1
控制器正在使用Devise进行身份验证,因此wget不幸地无法在未登录的情况下访问该页面。 - gjb
1
你是正确的,那确实会有问题。如果你还没有找到替代方案,可以考虑扩展你的应用程序以支持HTTP基本身份验证,当然,Devise也可以做到这一点,这样就很容易地仍然可以使用基本的wget方式。我能想到的唯一替代方案是查看缓存代码并尝试使用Ruby代码触发它,但我对这些函数不够熟悉,无法尝试。 - Leftblank
一个很好的建议,谢谢。但是,我决定采用 @bjpirt 的答案,利用 curl 的 cookie 支持。 - gjb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接