Rails 缓存值 lost/nil 尽管 expires_in 24.hours

Rails cached value lost/nil despite expires_in 24.hours

我正在使用 ruby 2.3.3 和 Rails 4.2.8 和 Puma(1 个工作人员,5 个线程),在我的管理(即不重要)页面上我想显示一些统计信息(整数值)来自我的数据库。有些请求需要很长时间才能执行,所以我决定缓存这些值并使用 rake 任务每天重写它们。

Admin#index 控制器

require 'timeout'
begin
  timeout(8) do
    @products_a = Rails.cache.fetch('products_a', :expires_in => 24.hours) { Product.where(heavy_condition_a).size }

    @products_b = Rails.cache.fetch('products_b', :expires_in => 24.hours) { Product.where(heavy_condition_b).size }
    @products_c = Rails.cache.fetch('products_c', :expires_in => 24.hours) { Product.where(heavy_condition_c).size }
    @products_d = Rails.cache.fetch('products_d', :expires_in => 24.hours) { Product.where(heavy_condition_d).size }              
  end
rescue Timeout::Error
  @products_a = 999
  @products_b = 999
  @products_c = 999
  @products_d = 999   

end

Admin#index view

    <li>Products A: <%= @products_a %></li>
    <li>Products B: <%= @products_b %></li>
    <li>Products C: <%= @products_c %></li>
    <li>Products D: <%= @products_d %></li>

耙任务

task :set_admin_index_stats => :environment do
    Rails.cache.write('products_a', Product.where(heavy_condition_a).size, :expires_in => 24.hours)
    Rails.cache.write('products_b', Product.where(heavy_condition_b).size, :expires_in => 24.hours)
    Rails.cache.write('products_c', Product.where(heavy_condition_c).size, :expires_in => 24.hours)
    Rails.cache.write('products_d', Product.where(heavy_condition_d).size, :expires_in => 24.hours)                     
end

我在生产中使用它并使用 Memcachier(在 Heroku 上)作为缓存存储。我还将它用于网站上的页面缓存,并且在那里工作正常。我有:

production.rb

config.cache_store = :dalli_store

我遇到的问题是缓存的值几乎立即从缓存中消失,而且间歇性消失。在我试过的控制台中:

  1. 我Rails.cache.write一个值(例如product_a)一分钟后查看,它还在。虽然很粗糙,但我可以在 Memcachier 管理工具中看到 "Set cmds" 递增 1。
  2. 但是,当我添加下一个值(例如 product_b)时,第一个值消失了(变为零)!有时,如果我将所有 4 个值相加,2 似乎会保留下来。这些并不总是相同的值。就像打地鼠一样!
  3. 如果我 运行 rake 写入值然后尝试读取值,通常只留下两个值,而其他值丢失。

我看到过一个与此相关的类似问题,其中解释的原因是使用了多线程服务器。缓存的值保存在一个线程中,无法在另一个线程中访问,解决方案是使用内存缓存,我就是这样做的。

不仅仅是控制台。如果我只是重新加载 admin#index 视图来存储值或 运行 rake 任务,我会遇到同样的问题。这些价值观不坚持。

我怀疑我没有正确使用 Rails.cache 命令,或者这些命令实际上没有使用 Memcachier。我无法确定我的值是否实际上存储在 Memcachier 中,但是当我在控制台中使用我的第一个命令时,我确实得到以下信息:

Rails.cache.read('products_a')
Dalli::Server#connect mc1.dev.eu.ec2.memcachier.com:11211
Dalli/SASL authenticating as abc123
Dalli/SASL authenticating as abc123
Dalli/SASL: abc123
Dalli/SASL: abc123
=> 0

但我没有得到后续写入的信息(我认为这是控制台中的可读性问题,而不是未使用 Memcachier 的证据。

我在这里错过了什么?为什么这些值不会保留在我的缓存中?

Heroku DevCenter 声明了一些不同的缓存配置,并给出了一些关于线程化 Rails 应用程序服务器的建议,例如 Puma 使用 connection_pool gem:

config.cache_store = :mem_cache_store,
  (ENV["MEMCACHIER_SERVERS"] || "").split(","),
  { :username => ENV["MEMCACHIER_USERNAME"],
    :password => ENV["MEMCACHIER_PASSWORD"],
    :failover => true,
    :socket_timeout => 1.5,
    :socket_failure_delay => 0.2,
    :down_retry_delay => 60,
    :pool_size => 5
  }