Skip to content

refactor(remote-config): Add mergeItemsBlobData to RemoteConfigManager#3725

Merged
tonidero merged 7 commits into
mainfrom
batch-blobdata
Jul 7, 2026
Merged

refactor(remote-config): Add mergeItemsBlobData to RemoteConfigManager#3725
tonidero merged 7 commits into
mainfrom
batch-blobdata

Conversation

@tonidero

@tonidero tonidero commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

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 single T.


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 mergeItemsBlobData on RemoteConfigManager so callers can load several topic items in one shot instead of repeated blobData calls.

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 @Serializable type—or returns null with logging when anything is missing, non-JSON, or fails deserialization (all-or-nothing). Empty key lists and the existing 4xx disabled kill-switch also yield null without I/O.

Tests cover the happy path, failure modes, disabled endpoint behavior, and a single shared on-demand /v1/config sync 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.

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>
@tonidero tonidero added the pr:feat A new feature label Jul 6, 2026
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>
@tonidero tonidero changed the title Add batch blobData overloads to RemoteConfigManager Add mergeItemsBlobData to RemoteConfigManager Jul 6, 2026
@tonidero tonidero added pr:other feat:remote-config and removed pr:feat A new feature labels Jul 6, 2026
@tonidero tonidero changed the title Add mergeItemsBlobData to RemoteConfigManager refactor(remote-config): Add mergeItemsBlobData to RemoteConfigManager Jul 6, 2026
* 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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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? {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lmk what you think of this API @vegaro @rickvdl . I think usage now should be something like:

mergeItemsBlobData<UiConfig>(RemoteConfigTopic.UiConfig, listOf(....))

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>
@tonidero tonidero marked this pull request as ready for review July 6, 2026 15:52
@tonidero tonidero requested a review from a team as a code owner July 6, 2026 15:52
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>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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

codecov Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.52%. Comparing base (7d93941) to head (94ee129).
⚠️ Report is 1 commits behind head on main.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ajpallares ajpallares left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense!

Just a small question about a test, but nothing blocking

@rickvdl rickvdl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

tonidero and others added 2 commits July 7, 2026 09:14
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>
@tonidero tonidero requested a review from rickvdl July 7, 2026 07:21

@rickvdl rickvdl left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Great API addition 💪

@tonidero tonidero added this pull request to the merge queue Jul 7, 2026

@vegaro vegaro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged via the queue into main with commit 8df6631 Jul 7, 2026
35 checks passed
@tonidero tonidero deleted the batch-blobdata branch July 7, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants