gpt4 book ai didi

ruby-on-rails - Rails 低级缓存 : Update cache when ActiveRecord object updated_at changes OR when a new object is added to collection

转载 作者:数据小太阳 更新时间:2023-10-29 07:24:25 29 4
gpt4 key购买 nike

Rails 附带片段缓存和低级缓存。片段缓存的工作原理非常清楚:

Rails will write a new cache entry with a unique key. If the value of updated_at has changed, a new key will be generated. Then Rails will write a new cache to that key, and the old cache written to the old key will never be used again. This is called key-based expiration. Cache fragments will also be expired when the view fragment changes (e.g., the HTML in the view changes). Cache stores like Memcached will automatically delete old cache files.


<% @products.each do |product| %>
<% cache product do %>
<%= render product %>
<% end %>
<% end %>

因此 View 将被缓存,当与 View 关联的 ActiveRecord 对象的 updated_at 更改或 html 更改时,将创建新的缓存。可以理解。

我不想缓存 View 。我想缓存从 ActiveRecord 查询构建的哈希集合。而且我知道 Rails 有 SQL 缓存,当在一个请求中使用时,它缓存相同查询的结果。但是我需要在多个请求中可用的结果,并且仅在对象之一的 updated_at 更改或将新对象添加到 Hash 集合时才更新。

低级缓存缓存特定值或查询结果,而不是缓存 View 片段。
def get_events
@events = Event.search(params)

time = Benchmark.measure {
event_data = Rails.cache.fetch 'event_data' do
# A TON OF EVENTS TO LOAD ON CALENDAR
@events.collect do |event|
{
title: event.title,
description: event.description || '',
start: event.starttime.iso8601,
end: event.endtime.iso8601,
allDay: event.all_day,
recurring: (event.event_series_id) ? true : false,
backgroundColor: (event.event_category.color || "red"),
borderColor: (event.event_category.color || "red")
}
end
end

}
Rails.logger.info("CALENDAR EVENT LOAD TIME: #{time.real}")

render json: event_data.to_json
end

但是现在我认为如果更新了其中一个事件或向集合中添加了新的散列,缓存不会过期。我怎样才能做到这一点?

最佳答案

Rails.cache.fetch 是读写的快捷方式

我们试图对缓存做的是:

value = Rails.cache.read( :some_key )
if value.nil?
expected_value = ...
Rails.cache.write( :some_key, expected_value )
end

我们首先尝试从缓存中读取,如果不存在任何值,那么我们从任何地方检索数据,将其添加到缓存中并执行您需要对它执行的任何操作。

在接下来的调用中,我们将尝试再次访问 :some_key缓存键,但这次它会存在,我们不需要再次检索该值,我们只需要获取已经缓存的值。

这是什么 fetch一次性完成所有操作:
value = Rails.cache.fetch( :some_key ) do
# if :some_key doesn't exist in cache, the result of this block
# is stored into :some_key and gets returned
end

这只不过是一个非常方便的快捷方式,但了解其行为很重要。

我们如何处理我们的低级缓存?

这里的关键(双关语)是选择一个缓存键,当缓存数据与底层数据不同步时,该键会发生变化。这通常比更新现有缓存值更容易:相反,请确保不要重用存储旧数据的缓存键。

例如,要将所有事件数据存储在缓存中,我们会执行以下操作:
def get_events
# Get the most recent event, this should be a pretty fast query
last_modified = Event.order(:updated_at).last
# Turns a 2018-01-01 01:23:45 datetime into 20180101220000
# We could use to_i or anything else but examples would be less readable
last_modified_str = last_modified.updated_at.utc.to_s(:number)
# And our cache key would be
cache_key = "all_events/#{last_modified_str}"

# Let's check this cache key: if it doesn't exist in our cache store,
# the block will store all events at this cache key, and return the value
all_events = Rails.cache.fetch(cache_key) do
Event.all
end

# do whatever we need to with all_events variable
end

这里真正重要的是:
  • 主要数据加载发生在 fetch 内堵塞。千万不要每次进入这个方法就触发,不然就失去了所有缓存的兴趣。
  • key 的选择是派拉蒙 !它必须 :
  • 一旦您的数据变得陈旧,请立即更改 .否则,您将使用旧数据命中“旧”缓存键,并且不会提供最新数据。
  • 但! 确定缓存键的成本必须比检索缓存数据的成本低很多 ,因为每次传入此方法时,您都将“计算”缓存键是什么。因此,如果确定缓存键比检索实际数据花费的时间更长,那么,也许您将不得不以不同的方式思考问题。

  • 使用此先前方法的示例

    让我们看看我以前的 get_events方法的行为举一个例子。假设我们有以下 Events在您的数据库中:
    | ID | Updated_at       | 
    |----|------------------|
    | 1 | 2018-01-01 00:00 |
    | 2 | 2018-02-02 00:00 |
    | 3 | 2018-03-03 00:00 |

    第一次通话

    此时,我们调用 get_events .事件 #3 是最近更新的事件,因此 Rails 将检查缓存键 all_events/20180303000000 .它尚不存在,因此将从 DB 请求所有事件并使用此缓存键存储到缓存中。

    相同数据,后续调用

    如果您不更新这些事件中的任何一个,所有接下来的调用都将调用 get_events将命中缓存键 all_events/20180303000000现在存在并包含所有事件。因此,您不会访问数据库,而只是使用缓存中的值。

    如果我们修改一个事件怎么办?
    Event.find(2).touch

    我们修改了事件 #2,所以以前存储在缓存中的内容不再是最新的。我们现在有以下事件列表:
    | ID | Updated_at       | 
    |----|------------------|
    | 1 | 2018-01-01 00:00 |
    | 2 | 2018-04-07 19:27 | <--- just updated :)
    | 3 | 2018-03-03 00:00 |

    下次调用 get_events将采用最近的事件(现在#2),因此尝试访问缓存键 all_events/20180407192700 ……还不存在! Rails.cache.fetch将评估 block ,并将当前状态的所有当前事件放入这个新 key all_events/20180407192700 .而且您不会得到陈旧的数据。

    你的具体问题呢?

    您必须找到正确的缓存键,并使其能够在 fetch 内完成事件数据加载。堵塞。

    由于您使用 params 过滤事件,缓存将取决于您的参数,因此您需要找到一种方法将参数表示为字符串以将其集成到您的缓存键中。缓存的事件会因一组参数而异。

    为这些参数查找最近更新的事件,以避免检索过时的数据。我们可以使用 ActiveRecord cache_key任何 ActiveRecord 对象上的方法作为其缓存键,这很方便并且避免了像我们之前所做的那样繁琐的时间戳格式化。

    这应该给你类似的东西:
    def get_events
    latest_event = Event.search(params).order(:updated_at).last
    # text representation of the given params

    # Check https://apidock.com/rails/ActiveRecord/Base/cache_key
    # for an easy way to define cache_key for an ActiveRecord model instance
    cache_key = "filtered_events/#{text_rep_of_params}/#{latest_event.cache_key}"

    event_data = Rails.cache.fetch(cache_key) do
    events = Event.search(params)
    # A TON OF EVENTS TO LOAD ON CALENDAR
    events.collect do |event|
    {
    title: event.title,
    description: event.description || '',
    start: event.starttime.iso8601,
    end: event.endtime.iso8601,
    allDay: event.all_day,
    recurring: (event.event_series_id) ? true : false,
    backgroundColor: (event.event_category.color || "red"),
    borderColor: (event.event_category.color || "red")
    }
    end
    end

    render json: event_data.to_json
    end

    瞧!我希望它有所帮助。祝你的实现细节好运。

    关于ruby-on-rails - Rails 低级缓存 : Update cache when ActiveRecord object updated_at changes OR when a new object is added to collection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49699795/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com