Skip to content

Conversation

@KyleAMathews
Copy link
Collaborator

Fix a race condition in WebLocksLeader where transactions could be replayed twice on page load. The issue occurred because:

  1. requestLeadership() returned true immediately when lock was available
  2. But notifyLeadershipChange(true) was called asynchronously when the fire-and-forget navigator.locks.request() actually acquired the lock
  3. This caused loadAndReplayTransactions() to be called twice - once manually and once via the callback

The fix sets isLeaderState = true synchronously when we know the lock is available, so the async notifyLeadershipChange(true) doesn't trigger the callback again (the guard checks isLeaderState !== isLeader).

Reported by Toba on Discord.

🎯 Changes

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

🚀 Release Impact

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

@changeset-bot
Copy link

changeset-bot bot commented Dec 18, 2025

🦋 Changeset detected

Latest commit: 350d887

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/offline-transactions Patch

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

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 18, 2025

More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1046

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1046

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1046

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1046

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1046

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1046

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1046

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1046

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1046

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1046

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1046

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1046

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1046

commit: 350d887

@github-actions
Copy link
Contributor

github-actions bot commented Dec 18, 2025

Size Change: 0 B

Total Size: 89.4 kB

ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection/change-events.js 1.39 kB
./packages/db/dist/esm/collection/changes.js 999 B
./packages/db/dist/esm/collection/events.js 388 B
./packages/db/dist/esm/collection/index.js 3.24 kB
./packages/db/dist/esm/collection/indexes.js 1.1 kB
./packages/db/dist/esm/collection/lifecycle.js 1.67 kB
./packages/db/dist/esm/collection/mutations.js 2.34 kB
./packages/db/dist/esm/collection/state.js 3.46 kB
./packages/db/dist/esm/collection/subscription.js 3.54 kB
./packages/db/dist/esm/collection/sync.js 2.38 kB
./packages/db/dist/esm/deferred.js 207 B
./packages/db/dist/esm/errors.js 4.27 kB
./packages/db/dist/esm/event-emitter.js 748 B
./packages/db/dist/esm/index.js 2.68 kB
./packages/db/dist/esm/indexes/auto-index.js 742 B
./packages/db/dist/esm/indexes/base-index.js 766 B
./packages/db/dist/esm/indexes/btree-index.js 1.93 kB
./packages/db/dist/esm/indexes/lazy-index.js 1.1 kB
./packages/db/dist/esm/indexes/reverse-index.js 513 B
./packages/db/dist/esm/local-only.js 837 B
./packages/db/dist/esm/local-storage.js 2.1 kB
./packages/db/dist/esm/optimistic-action.js 359 B
./packages/db/dist/esm/paced-mutations.js 496 B
./packages/db/dist/esm/proxy.js 3.75 kB
./packages/db/dist/esm/query/builder/functions.js 733 B
./packages/db/dist/esm/query/builder/index.js 3.96 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 917 B
./packages/db/dist/esm/query/compiler/evaluators.js 1.35 kB
./packages/db/dist/esm/query/compiler/expressions.js 430 B
./packages/db/dist/esm/query/compiler/group-by.js 1.8 kB
./packages/db/dist/esm/query/compiler/index.js 1.96 kB
./packages/db/dist/esm/query/compiler/joins.js 2 kB
./packages/db/dist/esm/query/compiler/order-by.js 1.46 kB
./packages/db/dist/esm/query/compiler/select.js 1.07 kB
./packages/db/dist/esm/query/expression-helpers.js 1.43 kB
./packages/db/dist/esm/query/ir.js 673 B
./packages/db/dist/esm/query/live-query-collection.js 360 B
./packages/db/dist/esm/query/live/collection-config-builder.js 5.33 kB
./packages/db/dist/esm/query/live/collection-registry.js 264 B
./packages/db/dist/esm/query/live/collection-subscriber.js 1.9 kB
./packages/db/dist/esm/query/live/internal.js 130 B
./packages/db/dist/esm/query/optimizer.js 2.56 kB
./packages/db/dist/esm/query/predicate-utils.js 2.97 kB
./packages/db/dist/esm/query/subset-dedupe.js 921 B
./packages/db/dist/esm/scheduler.js 1.3 kB
./packages/db/dist/esm/SortedMap.js 1.3 kB
./packages/db/dist/esm/strategies/debounceStrategy.js 247 B
./packages/db/dist/esm/strategies/queueStrategy.js 428 B
./packages/db/dist/esm/strategies/throttleStrategy.js 246 B
./packages/db/dist/esm/transactions.js 2.9 kB
./packages/db/dist/esm/utils.js 881 B
./packages/db/dist/esm/utils/browser-polyfills.js 304 B
./packages/db/dist/esm/utils/btree.js 5.61 kB
./packages/db/dist/esm/utils/comparison.js 852 B
./packages/db/dist/esm/utils/cursor.js 457 B
./packages/db/dist/esm/utils/index-optimization.js 1.51 kB
./packages/db/dist/esm/utils/type-guards.js 157 B

compressed-size-action::db-package-size

@github-actions
Copy link
Contributor

github-actions bot commented Dec 18, 2025

Size Change: 0 B

Total Size: 3.35 kB

ℹ️ View Unchanged
Filename Size
./packages/react-db/dist/esm/index.js 225 B
./packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.17 kB
./packages/react-db/dist/esm/useLiveQuery.js 1.12 kB
./packages/react-db/dist/esm/useLiveSuspenseQuery.js 431 B
./packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

@KyleAMathews KyleAMathews force-pushed the claude/investigate-discord-bug-TD4bH branch 3 times, most recently from 4171209 to 414db19 Compare December 19, 2025 15:45
…nitialization

Fix a race condition in WebLocksLeader where transactions could be
replayed twice on page load. The issue occurred because:

1. requestLeadership() returned true immediately when lock was available
2. But notifyLeadershipChange(true) was called asynchronously when the
   fire-and-forget navigator.locks.request() actually acquired the lock
3. This caused loadAndReplayTransactions() to be called twice - once
   manually and once via the callback

The fix has two parts:
1. Set WebLocksLeader.isLeaderState = true synchronously when we know
   the lock is available, so the async notifyLeadershipChange(true)
   doesn't trigger the callback again
2. Set OfflineExecutor.isLeaderState based on requestLeadership() return
   value, since we can no longer rely on the callback to set it

Reported by Toba on Discord.
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.

3 participants