fix(remote-config): Remote-config fixes/improvements#3714
Merged
Conversation
Contributor
Author
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3714 +/- ##
==========================================
+ Coverage 80.56% 80.57% +0.01%
==========================================
Files 398 398
Lines 16473 16488 +15
Branches 2356 2356
==========================================
+ Hits 13271 13286 +15
- Misses 2265 2266 +1
+ Partials 937 936 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
d0e238a to
653b269
Compare
Open
2 tasks
Fixes from a review pass over the remote-config stack: - ConfigItemSerializer throws SerializationException (not ISE) for a non-object topic item, so a malformed server payload is a recoverable parse failure instead of an uncaught crash. - RemoteConfigBlobStore writes via AtomicFile (matching the disk cache), so a killed process can never leave a partial blob under a valid ref. - RemoteConfigDiskCache keeps an in-memory snapshot of the persisted state, so hot-path reads stop re-reading + re-parsing the file (and recomputing contentHash) on every call. - RemoteConfigManager runs its disk IO on the manager scope: pre-request reads hop off the caller thread, and persist() is split into commitConfig (under cacheLock) + syncBlobs (outside it) so clearCache on an identity change is never blocked behind blob IO. The clearCache file wipe stays synchronous by design: deferring it to a parallel IO job could run after a subsequent new-user commit and delete it. Plus tests: failed refresh does not stamp the staleness window, rate-limited syncAttributesAndOfferings branch does not refresh, persisted-file forward-compat with unknown keys, and a concurrency stress (readers x clearCache x refreshes). Test plan: - ./gradlew detektAll - ./gradlew :purchases:testDefaultsBc8DebugUnitTest - Backend integration tests against production Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pulls the "disk IO off the caller thread" change out of this PR to keep it small: RemoteConfigManager is restored to the stack parent's version (persist() back under cacheLock, pre-request disk reads synchronous), and the two tests specific to that behavior are removed. The fix and its ordering-hazard rationale are recoverable from this PR's history. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
653b269 to
a031979
Compare
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.

Hardening fixes from a review pass over the remote-config stack.
Changes
ConfigItemSerializerthrowsSerializationException(instead of the.jsonObjectaccessor'sIllegalStateException, which escaped the manager's catch) for a non-object item, making it a recoverable parse failure.RemoteConfigBlobStorewrites viaAtomicFile(same scheme as the disk cache), so a process kill can never leave a partial blob file under a valid ref.RemoteConfigDiskCache: hot-path reads (topic()/blobData(), blob-source lookups per download) stop re-reading + re-parsing the file and recomputingcontentHashon every call.Tests
SerializationException; manager keeps the cache, releases the guard, no crash..neworphan is pruned byretainOnly.clear(); fresh instances still read from disk.syncAttributesAndOfferingsbranch does not force a refresh.clearCache+ refreshes all complete, manager stays functional.Note
Medium Risk
Changes affect on-disk config/blob caching and config parse error handling on a hot SDK path; behavior is defensive and well-covered by tests, but incorrect snapshot or atomic-write semantics could cause stale config or missed updates.
Overview
Hardens the remote-config persistence and parsing stack so bad payloads and crashes are handled safely, and hot-path disk access is cheaper.
ConfigItemSerializernow throwsSerializationExceptionwhen a topic item is not a JSON object (instead ofIllegalStateExceptionfrom.jsonObject), soRemoteConfigManagercan treat malformed config as a recoverable parse failure without crashing.RemoteConfigBlobStoreswitches blob persistence toAtomicFile(same pattern as the disk cache), so a killed process cannot leave a partial file under a valid ref;retainOnlydocs/tests now cover<ref>.neworphans instead ofrc_blob_*.tmp.RemoteConfigDiskCacheadds a synchronized in-memory snapshot:read()loads from disk once (including caching a miss),write()updates the snapshot only after a durable write, andclear()resets the snapshot before deleting the file.Tests cover interrupted blob writes, snapshot behavior, forward-compatible persisted JSON, failed refresh / rate-limited sync not over-refreshing, non-object topic items, and a concurrency stress run over
clearCache+ refreshes +topic()reads.Reviewed by Cursor Bugbot for commit a031979. Bugbot is set up for automated code reviews on this repo. Configure here.