Repository navigation
Add opt-in handling for cache provider errors (1.4.0) - #28
Open
skunkworker wants to merge 5 commits into
Open
skunkworker wants to merge 5 commits into
skunkworker wants to merge 5 commits into
Conversation
Brings the :handle_cache_error and :cache_error_proc options from the unmerged PR #16 (released internally as 0.3.0.rc2) forward onto 1.3.0. When :handle_cache_error is true, an error from the cache provider acts as a cache miss and goes to :cache_error_proc. Both are off by default. An error from the fetch block (the RPC call, or RemoteRecordNotFound from a bang finder) still goes to the caller, and the block runs at most once. fetch keeps the provider fetch, so :race_condition_ttl keeps working. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An error from the fetch block (the RPC call) goes to the caller and leaves the cache empty, with :handle_cache_error on or off. The README now says that a cache outage sends each finder call to the remote service, which increases its load until the cache comes back. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
delete, exist?, read and write now use one failsafe helper in place of four copies of the same rescue. FetchBlockResult tracks a run flag and builds the provider block itself, so fetch no longer needs the block && block_result guard. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The nested cache and the cache provider each get their own failsafe, so a handled error in the nested cache no longer skips the provider. - The cleanup delete in fetch never raises, so a failed delete no longer discards the value from the remote service. - An error from :cache_error_proc is written to stderr and does not replace the result. - A provider error whose cause chain holds the block error is treated as the block error, so it is not reported as a cache error. - The README says the two options apply only in default_options. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR brings the cache error handler from #16 forward onto 1.3.0.
#16 ("Handle cache failures", 2023) added
:handle_cache_errorand:cache_error_proc. It got approval, and it went out as the internal release0.3.0.rc2. Nobody merged it, and 1.0.0 to 1.3.0 started frommasterwithout it. alfred still pins0.3.0.rc2for this handler, so it cannot move to 1.3.0 without a change in behavior.Changes
Cache#read,#write,#delete,#exist?and#fetchrescue aStandardErrorfrom the cache provider. Whendefault_options[:handle_cache_error]is true, the error goes to:cache_error_procand the call acts as a cache miss. When it is not true, the error goes to the caller, as in 1.3.0.fetchblock (the RPC call, orRemoteRecordNotFoundfrom a bang finder) always goes to the caller. It never goes to:cache_error_proc, and it never goes into the cache.delete,exist?,readandwriteshare one privatefailsafehelper for the rescue. With nested caching, the nested cache and the cache provider each get their own failsafe, so an error in one does not skip the other.:cache_error_procraises, the library writes a warning to stderr, and the call continues.causechain holds the block error counts as the block error. It goes to the caller and is not reported as a cache error.fetchblock runs at most once. If the provider fails after the block ran (for example, on the write),fetchreturns the value from that run and does not call the RPC again.fetchkeeps the providerfetch. Handle cache failures #16 changed it toreadthenwrite, which turned off:race_condition_ttl. This PR does not.VERSIONis1.4.0.Design rule
A cache outage must not stop calls to the RPC services. With
:handle_cache_erroron, each finder call goes to the remote service while the cache is down. This increases the load on that service, and that is the expected trade-off.Change in behavior for all apps
Both options are off by default. One change applies to every app, with or without the handler: the cleanup
deleteinfetch(for a nil or empty value) no longer raises. Before, a failed delete raised and the caller lost the value from the remote service. Nowfetchreturns the value, and the nil or empty entry stays until its TTL ends. The README "Upgrading to 1.4.0" section records this.Evidence
22 new specs (cache methods, finder level, fetch block errors not cached, one block run, options not passed to the provider, no-block
fetch, nested cache errors, proc errors, wrapped block errors, cleanup delete errors). The 7 code review specs fail on the earlier commit (6 of them) or prove the block path under nested caching.Full suite: 213 examples, 0 failures on MRI 3.4.9 with
active_remote6.1, 7.1 and 8.0, on JRuby 10.0.6.0, and on JRuby 9.4.14.0. RuboCop: 19 files, no offenses.Probe with an RPC error (activesupport 7.1.6): the error goes to the caller, and the cache has 0 entries, with the handler off and on.
Probe with a cache entry that fails to deserialize:
After merge
0.3.0.rc2pin and the internal source block. Keep the initializer.🤖 Generated with Claude Code