如何针对单个请求或代码块绕过 Rails.cache?

Bre*_*ach 5 ruby caching ruby-on-rails activesupport

我有一个 API 端点,它从代码中聚合大量数据,这些代码利用 Rails.cache 来获取各处的小数据。然而,有时我想要 100% 的最新数据,就好像 Rails.cache 为空一样。显然,我可以在聚合数据之前清除缓存,但这会影响不相关的数据和请求。

有没有办法让我在 Rails 中发出一个请求,就像 Rails.cache 为空一样,类似于 Rails.cache 配置为 :null_store ?

ActiveRecord 中的查询缓存具有类似这样的功能 - 您可以将块传递到的“未缓存”函数,该块将在不启用查询缓存的情况下运行。我需要类似的东西,但是对于 Rails.cache 一般而言。

Bre*_*ach 2

由于似乎没有现成的解决方案,因此我通过将以下代码添加为 config/initializers/rails_cache.rb 编写了自己的解决方案

module Rails
  class << self
    alias :default_rails_cache :cache
    def cache
      # Allow any thread to override Rails.cache with its own cache implementation.
      RequestStore.store[:rails_cache] || default_rails_cache
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这允许任何线程指定自己的缓存存储,然后将其用于所有获取、读取和写入。因此,它不会从默认的 Rails.cache 中读取,也不会将其值写入默认的 Rails.cache。

如果线程长时间运行并且受益于启用缓存,您可以轻松地将其设置为其自己的 MemoryStore 实例:

RequestStore.store[:rails_cache] = ActiveSupport::Cache.lookup_store(:memory_store)
Run Code Online (Sandbox Code Playgroud)

如果您想完全关闭该线程的缓存,可以使用 :null_store 而不是 :memory_store。

如果您不使用 request_store gem,则可以将“RequestStore.store”替换为“Thread.current”以获得相同的效果 - 只需要更加小心跨请求的线程重用。