rails: Rails.cache.fetch unable to retrieve previous cached value if expired
Steps to reproduce
key = 'foo'
args = { expires_in: 10 }
Rails.cache.fetch(key, args) { 'bing' }
sleep(10)
entry = Rails.cache.send(:read_entry, key, args)
begin
Rails.cache.fetch(key, expires_in: 10) { raise 'error' }
rescue StandardError
# nice to have to reset original cache value
Rails.cache.write(key, entry.value, args) if entry&.expired? # write back into the cache the original value and reset cache
entry&.value
end
Problem statement
If an unexpected error occurs within the yield block say to a service call being down for a short period, it would be nice to provide the option to retrieve the existing cached value and re inject the value back into the cache to check again when the new cache period expires. This would allow servers to continue to function with a value rather than crashing because a consuming service went down for retrieving updates making my server more resilient to other consuming service problems.
Actual behavior
If the yield block fails, the previous cached value is deleted and no longer accessible after the fact.
Enhancement request
My suggestion is to move read_entry
to be publicly accessible allowing consumers to first hold the previous result prior to calling the fetch
. If the fetch
yields an error, the consumer can then catch their acceptable errors, determine their acceptable retries for exponential backoff, and then write
back into the cache their wait period for attempting the ‘refresh’ of their cached content.
System configuration
Rails version: 5.2 or greater Ruby version: 2.6 or greater
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18 (10 by maintainers)
Commits related to this issue
- Make retrieval of cached entry scope to be public. Fixes #45311 — committed to poloka/rails by poloka 2 years ago
Wait, what am I saying? You’d just need to use Rails Cache without an expiration:
Alternatively, you could do: