Skip to content

fix(db-sqlite-persistence-core): persisted preload() hangs when upstream sync never calls markReady#1615

Open
PHILLIPS71 wants to merge 3 commits into
TanStack:mainfrom
PHILLIPS71:fix/persisted-preload-offline-hang
Open

fix(db-sqlite-persistence-core): persisted preload() hangs when upstream sync never calls markReady#1615
PHILLIPS71 wants to merge 3 commits into
TanStack:mainfrom
PHILLIPS71:fix/persisted-preload-offline-hang

Conversation

@PHILLIPS71

@PHILLIPS71 PHILLIPS71 commented Jun 25, 2026

Copy link
Copy Markdown

🎯 Changes

collection.preload() and toArrayWhenReady() hung forever when the upstream sync never called markReady(). This happens in when TanStack Query's networkMode: 'offlineFirst' pauses a query because the device is offline, paused queries never reach isSuccess or isError, so markReady() is never called, and consumers block indefinitely even though SQLite has local data available.

Fix

After ensureStarted() resolves (SQLite hydration complete), params.markReady() is now called directly in createWrappedSyncConfig, independent of the upstream sync. This is skipped in on-demand mode because no rows load at startup there, the upstream sync owns readiness in that case. If the upstream sync also calls markReady(), the second call is safely ignored by the lifecycle layer.

✅ Checklist

  • I have tested this code locally with pnpm test.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where preload() could hang when upstream synchronization never signals readiness.
    • Improved startup readiness handling to reliably complete loading on success or failure (unless cleaned up).
  • Tests

    • Added a regression test covering preload() completing even when synchronization never calls readiness signaling, and verifying the data is available afterward.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8dad952-1b68-4a10-a695-d72fb1431725

📥 Commits

Reviewing files that changed from the base of the PR and between e17122d and 6bb2bfd.

📒 Files selected for processing (1)
  • packages/db-sqlite-persistence-core/src/persisted.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/db-sqlite-persistence-core/src/persisted.ts

📝 Walkthrough

Walkthrough

Persisted SQLite sync startup now marks collections ready even when upstream sync never calls markReady, and runtime.syncMode is readable from wrapper code. A regression test covers collection.preload() completing against a persisted row under that condition.

Changes

Persisted preload readiness

Layer / File(s) Summary
Wrapped sync readiness
packages/db-sqlite-persistence-core/src/persisted.ts
syncMode becomes externally readable, and wrapped sync startup now marks ready in a finally path while respecting cleanup and on-demand mode.
Loopback startup and preload regression
packages/db-sqlite-persistence-core/src/persisted.ts, packages/db-sqlite-persistence-core/tests/persisted.test.ts, .changeset/free-rivers-like.md
Loopback startup now logs ensureStarted() failures and marks ready in finally; the new test checks preload() against a sync that never calls markReady, and the changeset records the patch release.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • KyleAMathews

Poem

A bunny hopped through startup light,
With preload fixed to load just right.
If sync forgot to ring the bell,
Ready still came hopping well. 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main fix and the affected package without unnecessary noise.
Description check ✅ Passed The description follows the template and includes the changes, testing, and release impact sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PHILLIPS71 PHILLIPS71 changed the title fix: persisted preload() hangs when upstream sync never calls markReady fix(db-sqlite-persistence-core): persisted preload() hangs when upstream sync never calls markReady Jun 25, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/db-sqlite-persistence-core/src/persisted.ts`:
- Around line 2563-2570: The loopback startup flow in ensureStarted() still
calls params.markReady() unconditionally in the finally block, which can race
with cleanup() and re-mark a cleaned-up collection ready. Update the persisted
loopback path to mirror the guarded wrapped path by checking
startupState.cleanedUp before calling params.markReady(). Keep the fix localized
around the runtime.ensureStarted().catch(...).finally(...) chain in persisted.ts
so the lifecycle transition stays valid even when startup finishes late.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b90cf813-03a8-4896-9265-35c0a866016b

📥 Commits

Reviewing files that changed from the base of the PR and between 45617c4 and e17122d.

📒 Files selected for processing (3)
  • .changeset/free-rivers-like.md
  • packages/db-sqlite-persistence-core/src/persisted.ts
  • packages/db-sqlite-persistence-core/tests/persisted.test.ts

Comment thread packages/db-sqlite-persistence-core/src/persisted.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant