-
Notifications
You must be signed in to change notification settings - Fork 159
Restore offline transactions to optimistic store upon restart the app #1169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
KyleAMathews
wants to merge
7
commits into
main
Choose a base branch
from
claude/investigate-offline-transactions-bug-2FDgc
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Restore offline transactions to optimistic store upon restart the app #1169
KyleAMathews
wants to merge
7
commits into
main
from
claude/investigate-offline-transactions-bug-2FDgc
Conversation
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
🦋 Changeset detectedLatest commit: 1eda746 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
More templates
@tanstack/angular-db
@tanstack/db
@tanstack/db-ivm
@tanstack/electric-db-collection
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
…refresh Add a failing test that demonstrates the issue where offline transactions do not restore optimistic state to the collection when the page is refreshed while offline. Users have to manually handle this in beforeRetry by replaying all transactions into the collection. The test asserts the expected behavior (optimistic data should be present after page refresh) and currently fails, demonstrating the bug.
c618c2c to
72f94f9
Compare
Contributor
|
Size Change: 0 B Total Size: 90.8 kB ℹ️ View Unchanged
|
Contributor
|
Size Change: 0 B Total Size: 3.7 kB ℹ️ View Unchanged
|
When the page is refreshed while offline with pending transactions, the optimistic state was not being restored to collections. Users had to manually replay transactions in `beforeRetry` to restore UI state. This fix: 1. In `loadPendingTransactions()`, creates restoration transactions that hold the deserialized mutations and registers them with the collection's state manager to display optimistic data immediately 2. Properly reconstructs the mutation `key` during deserialization using the collection's `getKeyFromItem()` method, which is needed for optimistic state lookup 3. Cleans up restoration transactions when the offline transaction completes or fails, allowing sync data to take over 4. Adds `waitForInit()` method to allow waiting for full initialization including pending transaction loading 5. Updates `loadAndReplayTransactions()` to not block on execution, so initialization completes as soon as optimistic state is restored
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Consolidate restorationTransactions.delete() to single point - Improve comments on restoration transaction purpose Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add try-catch isolation in restoreOptimisticState to prevent one bad transaction from breaking all restoration - Add defensive null check for mutation.collection in cleanup methods - Add test for rollback of restored optimistic state on permanent failure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… cleanup Add catch handler to restoration transaction's isPersisted promise to prevent unhandled rejection when rollback() is called during cleanup. The rollback calls reject(undefined) which would otherwise cause an unhandled rejection error.
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.
Summary
Fixes offline transactions not restoring optimistic state when the page is refreshed while offline. Users now see their pending changes immediately on page load, providing a seamless offline UX.
Root Cause
When the
OfflineExecutorloaded pending transactions from storage on startup, it only scheduled them for execution—it never re-applied the mutations to the collection's state manager. The optimistic state lived only in memory and was lost on page refresh.Approach
Created "restoration transactions" that shadow the persisted offline transactions:
When pending transactions are loaded from storage, we:
Key Invariants
keypopulated for optimistic state to workNon-goals
Trade-offs
Alternative considered: Storing the optimistic state separately from the transaction data.
Why this approach: Reusing the existing transaction/mutation infrastructure is simpler and leverages the collection's built-in optimistic state management. No new storage schema or state reconciliation logic needed.
Verification
The new test
should restore optimistic state to collection on startupverifies the complete flow:Files Changed
OfflineExecutor.tsrestorationTransactionsmap,registerRestorationTransaction(),cleanupRestorationTransaction(), andwaitForInit()helperTransactionExecutor.tsrestoreOptimisticState()that creates restoration transactions on loadTransactionSerializer.tskeyfrom modified data during deserializationoffline-e2e.test.tsharness.ts