在我的应用程序中,有一个财务概览页面,其中包含很多查询。执行后台作业后,该页面每月刷新一次,因此我添加了缓存:
@iterated_hours = Rails.cache.fetch("productivity_data", expires_in: 24.hours) do
FinancialsIterator.new.create_productivity_iterations(@company)
end
后台作业完成后,缓存必须过期,因此我创建了一个模型CacheExpiration
:
class CacheExpiration < ApplicationRecord
validates :cache_key, :expires_in, presence: true
end
因此在后台作业中创建了一条记录:
CacheExpiration.create(cache_key: "productivity_data", expires_in: DateTime.now)
Rails.cache.fetch
已更新为:
expires_in = get_cache_key_expiration("productivity_data")
@iterated_hours = Rails.cache.fetch("productivity_data", expires_in: expires_in) do
FinancialsIterator.new.create_productivity_iterations(@company)
end
private def get_cache_key_expiration(cache_key)
cache_expiration = CacheExpiration.find_by_cache_key(cache_key)
if cache_expiration.present?
cache_expiration.expires_in
else
24.hours
end
end
所以现在将到期时间设置为DateTime
,这是正确的还是应该是几秒钟?这是确保后台作业完成时缓存仅过期一次的正确方法吗?
答案 0 :(得分:0)
显式设置expires_in
值是非常有限的,并且IMO容易出错。一旦创建了一个缓存值(您可以手动清除缓存),您将无法更改该值,并且如果您想更改后台作业以使其更多/更少地运行,您还必须记住更新expires_in
值。此外,完成后台作业的时间可能与对视图的第一个请求的时间不同。最坏的情况是,在后台作业更新视图信息之前一分钟发出请求。您的用户将需要等待一整天才能获得最新信息。
一种更灵活的方法是依赖ActiveRecord模型的updated_at
或不存在created_at
字段。
为此,您可以依赖已创建的CacheExpiration
模型(它可能已经具有适当的字段),也可以使用所创建的“大量记录”中的最后一个。只需订购它们,然后取最后SomeArModel.order(created_at: :desc).first
此方法的好处是,每当您创建/创建的AR模型被更新/创建时,缓存就会被破坏,并且将创建一个新的AR模型。用户调用终点的时间与后台作业运行的时间之间不再存在耦合。如果通过后台作业以外的任何方式创建记录,则也将对其进行简单处理。
在缓存方面,ActiveRecord模型是一等公民。您可以简单地将它们作为缓存键传递。然后,您的代码将更改为:
Rails.cache.fetch(CacheExpiration.find_by_cache_key("productivity_data")) do
FinancialsIterator.new.create_productivity_iterations(@company)
end
但是,如果有可能,请尝试查找替代模型,以便您不再需要维护CacheExpiration
。