fix(sentinel): SentinelFeignClientProperties#copy() should fail fast on Jackson errors#4329
Open
daguimu wants to merge 1 commit into
Open
Conversation
… Jackson errors The copy() method serializes/deserializes via Jackson to produce a deep backup used by CircuitBreakerRuleChangeListener for change detection in afterSingletonsInstantiated() and updateBackup(). On any serialization failure the previous catch (Exception ignored) silently returned a brand-new SentinelFeignClientProperties() with default values, dropping every user-configured rule. The listener then compared the live properties against that empty backup and treated every existing rule as "removed", triggering an erroneous full-rule refresh. Replace the silent fallback with throw new IllegalStateException(...) that wraps the original cause. Since Jackson 3 (tools.jackson) throws unchecked JacksonException, the try/catch was already legacy from the Jackson 2 (com.fasterxml.jackson) era; fail-fast surfaces the real issue at startup or refresh time instead of corrupting the diff baseline. Adds three unit tests covering: equal-but-distinct deep copy, copy independence from the original, and IllegalStateException propagation when Jackson serialization fails.
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.
Describe what this PR does / why we need it
SentinelFeignClientProperties#copy()is used byCircuitBreakerRuleChangeListenerto take a deep snapshot of the live properties (afterSingletonsInstantiated()line 105 andupdateBackup()line 190) so that the listener can detect whether circuit-breaker rules have changed when a refresh event arrives.The current implementation does a Jackson-based serialize/deserialize round-trip but swallows every exception with
catch (Exception ignored) { }and then returns a brand-new, default-valuedSentinelFeignClientProperties()— i.e. on any failure the backup ends up containing none of the user's configured rules. Because the listener subsequently compares the live properties against this empty backup (Objects.equals(properties, propertiesBackup)returnsfalse), every previously configured rule is treated as "removed" and an erroneous full-rule refresh is triggered.In addition, since the module has already migrated to Jackson 3 (
tools.jackson.databind.ObjectMapper),JacksonExceptionis unchecked (extendsRuntimeException). The originaltry / catch (Exception)was already a Jackson-2-era artefact and no longer serves any compile-time purpose.Does this pull request fix one issue?
NONE
Describe how you did it
Replaced the silent-swallow + new-instance fallback with
throw new IllegalStateException("Failed to deep-copy SentinelFeignClientProperties via Jackson", e);so that the original cause is preserved and surfaced fail-fast at the call site, instead of corrupting the diff baseline used by the rule-change listener.Describe how to verify it
Added a new unit test
SentinelFeignClientPropertiesTestwith three cases:copyReturnsEqualButDistinctInstance— confirmscopy()returns a value.equals()to the original but not the same reference.modifyingCopyDoesNotAffectOriginal— confirms the copy is a true deep copy (mutating the returnedMapdoes not mutate the source).copyFailsFastWhenJacksonCannotSerialize— uses an anonymous subclass whosegetRules()throws to force Jackson to fail; asserts the call now propagates anIllegalStateExceptionwhose cause is the underlying failure (this test fails against the pre-fix code, confirming the bug).Run:
Full module suite (18 tests including the integration tests) passes locally.
Special notes for reviews
IllegalStateExceptionis unchecked, so thecopy()signature is unchanged.copy()is called in two places. At startup (afterSingletonsInstantiated) a Jackson failure now becomes a startup failure with a meaningful cause, which is strictly better than silently shipping an empty backup. At refresh time (updateBackupinvoked fromonApplicationEvent), Spring'sSimpleApplicationEventMulticasterlogs listener exceptions and continues to other listeners, so the worst case is "this refresh cycle is skipped" rather than "rules are silently corrupted".+3 / -2in the production class plus one new test file.