首页 > 解决方案 > Rails.cache.read 在请求期间更改时不返回新值

问题描述

在 Web 请求期间,我发现Rails.cache.read如果在请求期间被另一个进程(例如另一个 Web 请求或 Rails 控制台)修改,后续调用不会反映最新值。我可以使用 WEBrick 使用香草 Rails 应用程序复制该问题,默认设置ActiveSupport::Cache::FileStore如下:

class WelcomeController < ApplicationController

  def index
    logger = Logger.new Rails.root.join('output.log')
    logger.info Rails.cache.read('foo')
    sleep 5
    logger.info Rails.cache.read('foo')
  end

end

假设foo键的起始值为alice。在sleep这里的 5 秒内,如果我Rails.cache.write 'foo', 'bob'在 Rails 控制台中运行,我希望记录以下内容:

I, [2019-08-22T18:05:04.551440 #48742]  INFO -- : alice
I, [2019-08-22T18:05:09.551971 #48742]  INFO -- : bob

但结果是:

I, [2019-08-22T18:05:04.551440 #48742]  INFO -- : alice
I, [2019-08-22T18:05:09.551971 #48742]  INFO -- : alice

在我刷新页面之前,似乎foo无法识别替换密钥数据的调用。请注意,这仅在作为 Web 请求运行时才会发生,而不是在从控制台调用相同代码时(WelcomeController.new.index例如调用 with)。

在我的实际项目中,我希望利用这种方法让 Web 请求等待另一个基于共享令牌的请求完成 - 但我对我的期望是否正确感到困惑。在项目本身中,puma 是 webserver,DalliStore 是内存存储,但结果是一样的。

标签: ruby-on-railsruby-on-rails-4cachingmemcached

解决方案


似乎正在发生的事情是ActiveSupport::Cache::FileStoreprependsStrategy::LocalCache反过来定义了机架中间件。这意味着每个机架请求只读取一次文件,并且该值存储在内存缓存中。除了以某种方式禁用该中间件之外,我没有看到避免这种情况的简单方法。


推荐阅读