【问题标题】:Rails: Scheduled task to warm up the cache?Rails:计划任务来预热缓存?
【发布时间】:2011-07-14 01:25:44
【问题描述】:

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

caches_action :complex_report, :expires_in => 1.day

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

页面当前在用户第一次请求时被缓存。然后从缓存中提取当天的后续请求。

这样做的问题是初始请求需要 20-30 秒才能加载。是否可以通过定时任务的方式提前填充缓存?

非常感谢任何建议。

【问题讨论】:

  • 页面渲染是否需要用户?也就是说,current_user 是否需要可供页面无错误地呈现?
  • 是的,current_user 被报告使用。

标签: ruby-on-rails ruby-on-rails-3 caching memcached


【解决方案1】:

这是对先前基于 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

希望这能奏效。当我尝试时似乎对我有用。

【讨论】:

  • 效果很好,谢谢。一个简洁的解决方案,不需要对现有代码进行任何修改。
【解决方案2】:

如果运行报告和收集结果的过程非常耗时,您可以使用Rails.cache.writeRails.cache.read 缓存这些结果(代替或同时缓存操作)。

然后,因为您不必担心身份验证或向服务器发出请求,运行查询和缓存来自 cron 作业的结果的行为会相当简单。

【讨论】:

  • 我喜欢这种方法 - 缓存出现在报表上的数据,而不是报表本身,然后改为预热该缓存。如果报表被频繁访问,甚至可能两者都值得做,但只是预热后端数据的缓存。
  • 感谢您的建议。这肯定有助于缓存复杂查询的结果,但是视图中也有一些条件格式(不同值的不同表格单元格样式)。出于这个原因,我更愿意缓存页面而不仅仅是数据。
【解决方案3】:

可能最基本的解决方案是设置一个简单的cron 条目来加载您希望拥有“热”缓存的页面。这可以很容易地使用crontab -e 将以下内容添加到服务器上用户的crontab 以打开编辑器:

*/15 * * * * wget -q @987654321@ &gt; /dev/null 2&gt;&amp;1

这将做的是使用wget 在提供的 url 中每 15 分钟获取数据,每小时、每天、每月和每年一次,忽略结果并且不发送 *nix 邮件以防出现问题。

【讨论】:

  • 控制器正在使用 Devise 进行身份验证,因此很遗憾 wget 在不登录的情况下无法访问该页面。
  • 你是对的,这将是一个问题。如果您还没有找到替代方案,则可以选择扩展您的应用程序以支持 HTTP 基本身份验证,当然 Devise 也可以这样做,这样很容易仍然可以使用基本的 wget 方式。我能想到的唯一选择是查看缓存代码并尝试使用 ruby​​ 代码触发它,但我对这些函数还不够熟悉,无法尝试。
  • 一个很好的建议,谢谢。但是,我决定采用@bjpirt 的回答并改用 curl 的 cookie 支持。
【解决方案4】:

看看这个宝石:

https://github.com/tommyh/preheat

gem 用于预热 Rails.cache。

来自文档: This will "preheat" all your Rails.cache.fetch calls on your homepage. It is as simple as that!

    #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 &

【讨论】:

    猜你喜欢
    • 2021-04-19
    • 1970-01-01
    • 2021-11-03
    • 2017-05-25
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多