Skip to content

Commit 307fdf8

Browse files
kevin-dpclaude
andauthored
fix: preload hangs forever after cleanup (#1576) (#1606)
* test: cover re-preloading a live query after cleanup Add a regression test asserting that a live query loads its data again when it is preloaded after the live query and its source collection were cleaned up (e.g. when switching data sets at runtime). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix: reset live query error state on sync restart so preload recovers after cleanup (#1576) A source collection that is cleaned up while a live query depends on it pushes the live query into an error state and latches `isInErrorState`. That flag was never reset, so when sync restarted via preload() after cleanup (e.g. switching profiles without a page refresh), updateLiveQueryStatus() returned early, markReady() was never called and the preload promise hung forever. Reset `isInErrorState` at the start of each sync session so the live query can become ready again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9a5e8e5 commit 307fdf8

3 files changed

Lines changed: 36 additions & 0 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@tanstack/db': patch
3+
---
4+
5+
Fix live query `preload()` hanging forever after a source collection was cleaned up (#1576)
6+
7+
When a source collection is cleaned up while a live query depends on it, the live query transitions to an error state and latches an internal `isInErrorState` flag. That flag was never reset, so restarting sync (e.g. calling `preload()` again after cleanup when switching profiles) left the live query unable to become ready and the returned promise never resolved. The flag is now cleared at the start of each sync session so the live query can recover.

packages/db/src/query/live/collection-config-builder.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ export class CollectionConfigBuilder<
596596
private syncFn(config: SyncMethods<TResult>) {
597597
// Store reference to the live query collection for error state transitions
598598
this.liveQueryCollection = config.collection
599+
// Reset error state from any previous sync session so a restarted sync can become ready again.
600+
this.isInErrorState = false
599601
// Store config and syncState as instance properties for the duration of this sync session
600602
this.currentSyncConfig = config
601603

packages/db/tests/query/live-query-collection.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,33 @@ describe(`createLiveQueryCollection`, () => {
594594
finalSubscription.unsubscribe()
595595
})
596596

597+
it(`loads its data again when preloaded after the live query and its source collection were cleaned up`, async () => {
598+
const activeUsers = createLiveQueryCollection({
599+
query: (q) =>
600+
q
601+
.from({ user: usersCollection })
602+
.where(({ user }) => eq(user.active, true)),
603+
})
604+
605+
await activeUsers.preload()
606+
expect(activeUsers.status).toBe(`ready`)
607+
expect(activeUsers.size).toBe(2)
608+
609+
// Tear down the source collection and the live query, e.g. when switching
610+
// to a different data set at runtime. Cleaning up a source collection puts
611+
// the dependent live query into an error state.
612+
await usersCollection.cleanup()
613+
expect(activeUsers.status).toBe(`error`)
614+
615+
await activeUsers.cleanup()
616+
expect(activeUsers.status).toBe(`cleaned-up`)
617+
618+
// Preloading again restarts sync and resolves once the data is loaded.
619+
await activeUsers.preload()
620+
expect(activeUsers.status).toBe(`ready`)
621+
expect(activeUsers.size).toBe(2)
622+
})
623+
597624
it(`should handle temporal values correctly in live queries`, async () => {
598625
// Define a type with temporal values
599626
type Task = {

0 commit comments

Comments
 (0)