Rails кэширует значение потеряно / ноль, несмотря на expires_in 24.hours
Я использую Ruby 2.3.3 и Rails 4.2.8 с Puma (1 рабочий, 5 потоков), и на моей странице администратора (т.е. не критично) я хочу показать некоторую статистику (целочисленные значения) из моей базы данных. Некоторые запросы выполняются довольно долго, поэтому я решил кэшировать эти значения и использовать задачу rake, чтобы перезаписывать их каждый день.
Admin# контроллер индекса
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# просмотр индекса
<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
Проблема, с которой я столкнулся, заключается в том, что кешированные значения почти мгновенно и довольно периодически исчезают из кеша. В консоли я пробовал:
- Я Rails.cache. Записываю одно значение (например, product_a) и проверяю его через минуту, оно все еще там. Хотя это и грубо, я могу видеть приращение "Set cmds" на единицу в инструменте администрирования Memcachier.
- Однако, когда я добавляю следующее значение (например, product_b), первое исчезает (становится нулем)! Иногда, если я складываю все 4 значения, кажется, что 2 прилипают. Это не всегда одни и те же ценности. Это похоже на удар крота!
- Если я запускаю грабли для записи значений, а затем пытаюсь прочитать значения, обычно остается только два значения, тогда как остальные теряются.
Я видел аналогичный вопрос, связанный с этим, где объясненная причина заключалась в использовании многопоточного сервера. Кешированное значение было сохранено в одном потоке и не могло быть достигнуто в другом, решение заключалось в использовании memcache, что я и делаю.
Это не только консоль. Если я просто перезагружу admin # index view, чтобы сохранить значения или запустить задачу 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 не используется.
Что мне здесь не хватает? Почему значения не остаются в моем кеше?
1 ответ
Heroku DevCenter заявляет немного другую конфигурацию кеша и дает несколько советов по многопоточным серверам приложений Rails, напримерPuma
с помощью connection_pool
драгоценный камень:
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
}