refactor(remote-config): Add mergeItemsBlobData to RemoteConfigManager#3725
Conversation
Let consumers fetch multiple items' blobs from a topic in a single, parallel call instead of issuing sequential per-item reads. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fetch multiple items from a topic in parallel and merge their JSON blobs into one object, decoded into a single T. Supports objects whose data is spread across several items in a topic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mergeItemsBlobData to RemoteConfigManager
| * logical object is assembled from data spread across several items in a topic (e.g. item `a` carries | ||
| * `{"x":...}` and item `b` carries `{"y":...}`, together decoding into `T(x, y)`). | ||
| * | ||
| * This is **all-or-nothing**: if any requested item is unknown, has no `blob_ref`, or its blob can't be |
There was a problem hiding this comment.
This was an assumption on my side. Lmk if you think we should proceed without some of the blobs, or if some of the blobs will be optional. Should probably modify this if so. @vegaro
There was a problem hiding this comment.
Hmm on one hand I think this makes sense, on the other hand (thinking about iOS), you could also say this is up to the object's decoder to decide? If it can live with one object missing, it should be able to construct the object?
Actually I changed my mind here, I think there's a difference between 'the value is null' or the value failed to fetch. So we probably shouldn't just treat it as the same. I think your tradeoff is the best here.
There was a problem hiding this comment.
I agree with you here, I don't see any reason to do something different for ui config for example
| * same ref. When the endpoint is [isDisabled] (the 4xx session kill-switch) every item resolves to `null`, | ||
| * so the call returns `null` without any read. Runs on [ioDispatcher]. | ||
| */ | ||
| suspend inline fun <reified T> mergeItemsBlobData(topic: RemoteConfigTopic, itemKeys: Collection<String>): T? { |
mergeItemsBlobData now nests each item's blob JSON under its item key
in the merged object (e.g. {"wf1": {...}, "wf2": {...}}) instead of
flattening the items together, so T declares a field per item key.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move JSON decoding into a non-inline mergeItemsBlobData(transform) worker that wraps resolve + merge + decode in one withContext, so decoding no longer runs on the caller's context (matching blobData and the KDoc). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2b458db. Configure here.
Add the isDisabled kill-switch guard that topic() and blobData already have, so a merged read returns null immediately without any read or misleading warn, including for an empty key list (which would otherwise build and decode an empty object). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3725 +/- ##
==========================================
+ Coverage 80.48% 80.52% +0.03%
==========================================
Files 403 403
Lines 16717 16750 +33
Branches 2386 2392 +6
==========================================
+ Hits 13455 13488 +33
Misses 2322 2322
Partials 940 940 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ajpallares
left a comment
There was a problem hiding this comment.
I think it makes sense!
Just a small question about a test, but nothing blocking
rickvdl
left a comment
There was a problem hiding this comment.
Few comments but looking very nice overall!
| * logical object is assembled from data spread across several items in a topic (e.g. item `a` carries | ||
| * `{"x":...}` and item `b` carries `{"y":...}`, together decoding into `T(x, y)`). | ||
| * | ||
| * This is **all-or-nothing**: if any requested item is unknown, has no `blob_ref`, or its blob can't be |
There was a problem hiding this comment.
Hmm on one hand I think this makes sense, on the other hand (thinking about iOS), you could also say this is up to the object's decoder to decide? If it can live with one object missing, it should be able to construct the object?
Actually I changed my mind here, I think there's a difference between 'the value is null' or the value failed to fetch. So we probably shouldn't just treat it as the same. I think your tradeoff is the best here.
Short-circuit mergeItemsBlobData to null for an empty itemKeys list (a no-op that would otherwise build and decode an empty object). Add tests covering a non-JSON blob and a merged object that fails to deserialize into T. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rickvdl
left a comment
There was a problem hiding this comment.
Awesome! Great API addition 💪

Why
Sometimes a single logical object in a remote-config topic needs data spread across multiple items. Previously a consumer would have to fetch each item's blob one by one. This adds
mergeItemsBlobData, which fetches the requested items' blobs in parallel, merges them into one JSON object, and decodes it into a singleT.Note
Low Risk
Additive read-side API on remote config that reuses existing blob resolution and sync behavior; no changes to persist/sync commit paths.
Overview
Adds
mergeItemsBlobDataonRemoteConfigManagerso callers can load several topic items in one shot instead of repeatedblobDatacalls.The API resolves each requested item’s blob in parallel (same rules as
blobData: on-demand sync, blob fetch deduping), nests each blob’s JSON under its item key (e.g.{"wf1":{...},"wf2":{...}}), then decodes into a single@Serializabletype—or returnsnullwith logging when anything is missing, non-JSON, or fails deserialization (all-or-nothing). Empty key lists and the existing 4xx disabled kill-switch also yieldnullwithout I/O.Tests cover the happy path, failure modes, disabled endpoint behavior, and a single shared on-demand
/v1/configsync when multiple uncached items are merged.Reviewed by Cursor Bugbot for commit 94ee129. Bugbot is set up for automated code reviews on this repo. Configure here.