Skip to content

Commit 167f262

Browse files
zzakbyroot
authored andcommitted
LocalCache with read_multi should respect version and expire
1 parent 9895615 commit 167f262

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

activesupport/lib/active_support/cache/strategy/local_cache.rb

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,25 @@ def read_multi_entries(names, **options)
129129
keys_to_names = names.index_by { |name| normalize_key(name, options) }
130130

131131
local_entries = local_cache.read_multi_entries(keys_to_names.keys)
132-
local_entries.transform_keys! { |key| keys_to_names[key] }
133-
local_entries.transform_values! do |payload|
134-
deserialize_entry(payload, **options)&.value
132+
133+
results = local_entries.each_with_object({}) do |(key, value), result|
134+
entry = deserialize_entry(value, **options)
135+
136+
normalized_key = keys_to_names[key]
137+
if entry.nil?
138+
result[normalized_key] = nil
139+
elsif entry.expired? || entry.mismatched?(normalize_version(normalized_key, options))
140+
local_cache.delete_entry(key)
141+
else
142+
result[normalized_key] = entry.value
143+
end
135144
end
136-
missed_names = names - local_entries.keys
137145

138-
if missed_names.any?
139-
local_entries.merge!(super(missed_names, **options))
140-
else
141-
local_entries
146+
if results.size < names.size
147+
results.merge!(super(names - results.keys, **options))
142148
end
149+
150+
results
143151
end
144152

145153
def write_serialized_entry(key, payload, **)

activesupport/test/cache/behaviors/local_cache_behavior.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,37 @@ def test_local_cache_of_read_multi
242242
end
243243
end
244244

245+
def test_local_cache_of_read_multi_with_expiry
246+
key = SecureRandom.uuid
247+
value = SecureRandom.alphanumeric
248+
@cache.with_local_cache do
249+
time = Time.now
250+
@cache.write(key, value, expires_in: 60)
251+
assert_equal value, @cache.read_multi(key)[key]
252+
Time.stub(:now, time + 61) do
253+
assert_nil @cache.read_multi(key)[key]
254+
end
255+
end
256+
end
257+
258+
def test_local_cache_of_read_multi_with_versions
259+
model = Struct.new(:to_param, :cache_version)
260+
261+
@cache.with_local_cache do
262+
thing = model.new(1, 1)
263+
key = ["foo", thing]
264+
265+
@cache.write(key, "contents")
266+
267+
assert_equal "contents", @cache.read(key)
268+
assert_equal "contents", @cache.read_multi(key)[key]
269+
270+
thing.cache_version = "002"
271+
assert_nil @cache.read(key)
272+
assert_nil @cache.read_multi(key)[key]
273+
end
274+
end
275+
245276
def test_local_cache_of_read_multi_prioritizes_local_entries
246277
key = "key#{rand}"
247278
@cache.with_local_cache do

0 commit comments

Comments
 (0)