Rails 6生产环境每日缓存块失效问题求助
问题排查与解决方案
核心问题分析
生产环境每次请求都刷新名言,说明缓存未正确命中,大概率是时区不一致或缓存键生成逻辑导致,也可能是缓存存储未正常工作。
分步解决方案
1. 统一缓存键的时区基准
Date.today依赖服务器系统时区,而Date.current遵循Rails应用配置的时区,二者不一致会导致缓存键生成错误(比如应用时区为巴黎时区,但服务器是UTC时区,会出现同一自然日生成不同缓存键的情况)。
修改控制器和视图的缓存键生成逻辑,统一使用Date.current并生成固定格式的日期字符串:
# 控制器代码 date_key = Date.current.strftime("%Y-%m-%d") @quote_of_the_day = Rails.cache.fetch("daily_quote_#{date_key}", expires_in: 1.day) do Quote.joins(:quote_tags).where(quote_tags: { id: 1 }).order("RANDOM()").limit(1).first end
# 视图代码 <% date_key = Date.current.strftime("%Y-%m-%d") %> <% cache("daily-quote-#{date_key}", expires_in: 24.hours) do %> <blockquote> <%= @quote_of_the_day.content.html_safe %> <figcaption> <% if @quote_of_the_day.book.present? %> <% if @quote_of_the_day.author.present? %> <%= @quote_of_the_day.author %> — <cite><%= @quote_of_the_day.book %></cite> <% else %> <cite><%= @quote_of_the_day.book %></cite> <% end %> <% elsif @quote_of_the_day.author.present? %> <%= @quote_of_the_day.author %> <% end %> </figcaption> </blockquote> <% end %>
2. 移除冗余的双重缓存
控制器的Rails.cache.fetch和视图的cache块属于双重缓存,虽功能可行但增加调试复杂度。可简化为只在视图层缓存整个内容块(包含数据查询),减少出错点:
<% cache("daily-quote-#{Date.current.strftime("%Y-%m-%d")}", expires_in: 1.day) do %> <% quote = Quote.joins(:quote_tags).where(quote_tags: { id: 1 }).order("RANDOM()").limit(1).first %> <blockquote> <%= quote.content.html_safe %> <figcaption> <% if quote.book.present? %> <% if quote.author.present? %> <%= quote.author %> — <cite><%= quote.book %></cite> <% else %> <cite><%= quote.book %></cite> <% end %> <% elsif quote.author.present? %> <%= quote.author %> <% end %> </figcaption> </blockquote> <% end %>
3. 验证Redis缓存连通性
登录生产环境Rails控制台,执行以下命令确认缓存存储是否正常工作:
# 写入测试缓存 Rails.cache.write("cache_test", "ok", expires_in: 30.minutes) # 读取测试缓存 Rails.cache.read("cache_test")
如果返回"ok",说明Redis缓存正常;如果返回nil,检查Redis地址配置、网络连通性或权限问题——这会导致Rails fallback到进程内内存缓存,不同请求会命中不同进程,表现为缓存不生效。
4. 检查时区配置一致性
在生产控制台执行以下命令,确认应用时区与系统时区是否匹配:
puts "应用时区: #{Rails.configuration.time_zone}" puts "系统时区: #{Time.now.zone}" puts "Date.today: #{Date.today.to_s}" puts "Date.current: #{Date.current.to_s}"
如果Date.today与Date.current返回不同日期,说明时区不一致,必须统一使用Date.current生成缓存键。
内容的提问来源于stack exchange,提问作者nico_lrx
相关产品推荐
相关产品推荐

