Rails 5.2+redis-rails片段缓存未自动过期问题咨询
排查Rails 5.2片段缓存touch后未更新的问题
我来帮你梳理几个可能导致这个问题的原因,以及对应的排查和解决方法:
1. 检查Site模型是否重写了cache_key方法
Rails片段缓存的键是基于对象的cache_key方法生成的,默认格式为"model_name/id-#{updated_at.utc.to_s(:number)}"。如果你的Site模型自定义了cache_key方法,但没有包含updated_at字段,那么即使执行touch更新了时间戳,缓存键也不会变化,自然不会触发缓存失效。
比如,如果你在模型里写了这样的代码:
class Site < ApplicationRecord def cache_key "sites/#{id}" end end
这就会导致缓存键固定为"sites/1"(假设id是1),touch后键不变,缓存不会更新。解决方法是恢复默认逻辑,或者在自定义方法里包含updated_at:
def cache_key "sites/#{id}-#{updated_at.utc.to_s(:number)}" end
2. 确认touch操作确实正确更新了updated_at
虽然你提到updated_at时间戳变更了,但可以再仔细验证一下:
- 在Rails控制台执行
@site.touch,然后立即执行@site.reload.updated_at,对比touch前后的时间是否有变化。 - 检查
Site模型是否有回调方法干扰了updated_at的更新,比如before_save回调手动设置了updated_at为某个固定值,或者阻止了字段的更新。 - 检查数据库表结构,确保
updated_at字段是datetime类型且允许自动更新(Rails默认会维护这个字段,但如果手动修改过迁移文件可能会出问题)。
3. 检查缓存存储的配置是否正确
使用redis-rails时,缓存存储的配置可能影响缓存键的处理:
- 确认
config.action_controller.cache_versioning的设置:Rails 5.2中这个配置默认是false,此时缓存键直接包含对象的cache_key(包含updated_at);如果手动开启了cache_versioning,需要确保对象的cache_version方法正确返回基于updated_at的值(默认是会的,但如果自定义了cache_version就需要检查)。 - 检查
config.cache_store的配置,确保使用的是:redis_cache_store且参数正确,比如没有设置错误的命名空间导致缓存隔离,或者序列化器配置异常影响缓存的读写。
4. 排查缓存键的生成是否符合预期
直接在视图或控制台里打印缓存键,确认touch前后是否变化:
在视图里添加临时调试代码:
<%= "Cache key: #{cache_key([@site, 'header'])}" %> <% cache [@site, "header"] do %> header goes here <% end %>
然后执行@site.touch刷新页面,看缓存键是否变化。如果键没变,那问题肯定出在键的生成逻辑上;如果键变了但还是显示旧内容,那可能是Redis缓存没有正确写入,或者存在缓存穿透的情况(比如Redis连接异常, fallback到了其他缓存存储)。
5. 检查是否存在缓存分层或代理问题
如果你的应用使用了多层缓存(比如CDN+Redis),即使Redis里的缓存失效了,CDN可能还缓存了旧内容。这种情况下需要检查CDN的缓存策略,确保片段缓存的响应头设置了正确的缓存失效规则,或者在touch操作时主动清除CDN对应路径的缓存。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

