Skip to content

Stop restarting a long-lived Source of Truth reader on every write - #765

Open
djain2405 wants to merge 1 commit into
MobileNativeFoundation:mainfrom
djain2405:fix/issue-572-sot-single-reader
Open

djain2405 wants to merge 1 commit into
MobileNativeFoundation:mainfrom
djain2405:fix/issue-572-sot-single-reader

Conversation

@djain2405

Copy link
Copy Markdown

Closes #572

Description

SourceOfTruthWithBarrier.reader collected the per-key barrier with flatMapLatest. Every write() moved that barrier from Blocked to Open, which cancelled delegate.reader(key) and collected it again.

That second collection is how a one-shot reader sees the written value. It also restarts a reader that stays open, such as Room, SQLDelight, or channelFlow. stream(StoreReadRequest.cached(key, refresh = true)) therefore collected the Source of Truth once per write. Yigit noted in #572 that this restart was unintentional, and that filtering reads during a write would keep the post-write Fetcher origin.

An active reader now stays subscribed across writes. A value that arrives while the barrier is blocked, or before this collector has observed the reopen, is held and emitted when the barrier opens. A successful write is still tagged Fetcher. A failed write still emits the WriteException first, and the following value stays SourceOfTruth. A reader is collected again only after its flow completes or fails, so one-shot and non-flow readers still re-read after a write. Cancelling the outer collector still cancels the child reader and releases the barrier. write(), delete(), and deleteAll() are unchanged. There is no public API change, and Store 6 is not part of this fix.

Two separate collectors of the same key still mean two reader subscriptions. This only removes the extra collection inside one collector.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Test Plan

Before the production change, longLivedReaderIsCollectedOnceAcrossWritesAndKeepsFetcherOrigin failed: after two writes the subscription count was 3, expected 1.

  • SourceOfTruthWithBarrierTests.longLivedReaderIsCollectedOnceAcrossWritesAndKeepsFetcherOrigin: a channelFlow reader stays at one subscription across two writes, the reader scope stays active, and the emissions are SourceOfTruth(null), Fetcher("a"), Fetcher("b"). Cancelling the collector sets the reader cancelled and returns barrierCount() to 0.
  • SourceOfTruthWithBarrierTests.longLivedReaderIsNotRestartedWhenWriteFails: a failed write stays at one subscription, emits WriteException, and does not restart the reader.
  • FlowStoreTests.givenLongLivedSourceOfTruthWhenCachedRefreshThenReaderIsCollectedOnce: stream(cached(key, refresh = true)) collects the Source of Truth once and emits Loading(Fetcher) then Data(Fetcher, "from-network").
  • Existing SourceOfTruthWithBarrierTests still cover the one-shot re-read, write failure then success, read failure then recovery, and a cancelled writer reopening the barrier.

Locally, on JDK 17: :store:jvmTest, :store:ktlintCheck, :store:apiCheck, and ./gradlew clean build koverXmlReport --continue.

Checklist:

Before submitting your PR, please review and check all of the following:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my change is effective
  • New and existing unit tests pass locally with my changes

Additional Notes:

No changelog entry. Store adds those at release time. The documentation checkbox is open because this does not change the public API or the documented read behavior.

@djain2405
djain2405 force-pushed the fix/issue-572-sot-single-reader branch from a2de5e3 to 8c1c704 Compare October 17, 2026 03:13

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🆕 Triage

Development

Successfully merging this pull request may close these issues.

[BUG] Cached(refresh = true) will collect SoT reader twice

1 participant