根据保存的值使缓存过期

时间:2019-02-18 08:24:28

标签: ruby-on-rails caching

在我的应用程序中,有一个财务概览页面,其中包含很多查询。执行后台作业后,该页面每月刷新一次,因此我添加了缓存:

@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,这是正确的还是应该是几秒钟?这是确保后台作业完成时缓存仅过期一次的正确方法吗?

1 个答案:

答案 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

铁路也有guide on that topic