Repository navigation
fix(query-core): unpause a mutation that can start after its onMutate - #11788
maxymlyskov wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
934a88c to
78b4a20
Compare
🦋 Changeset detectedLatest commit: d04f167 The changes in this PR will be included in the next version bump. This PR includes changesets to release 24 packages
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 |
Mutation.execute() computes isPaused before it awaits the MutationCache and mutation onMutate callbacks, and dispatches pending with that value. When the mutation cannot start at that point (queued behind another mutation in its scope, or offline) but can by the time onMutate resolves, retryer.start() runs it directly instead of going through pause(), so no continue action is dispatched and the mutation reports isPaused: true for its whole request. defaultShouldDehydrateMutation and resumePausedMutations read that flag, so the in-flight mutation is dehydrated as not yet sent and runs a second time after a restore. Dispatch continue right before start() when the mutation is still marked paused but can start now, as TanStack#9015 does for a restored mutation. Source: packages/query-core/src/mutation.ts execute(), packages/query-core/src/retryer.ts start(), hydration.ts defaultShouldDehydrateMutation.
78b4a20 to
d04f167
Compare
🎯 Changes
A mutation that can't start when
mutate()is called (queued behind another mutation in the same scope, or offline) starts aspendingwithisPaused: true. If it becomes able to start while itsonMutateis still running,retryer.start()runs themutationFnstraight away, but nothing dispatchescontinue, soisPausedstaystruefor the whole request.defaultShouldDehydrateMutationreads that flag, so the in-flight mutation gets dehydrated, and after a restoreresumePausedMutations()sends it again. Dehydrating while the second of two scoped mutations is in flight, then hydrating into a fresh client and resuming, main sendsa, b, band this branch sendsa, b. That is the case #6238 calls unwanted: an in-flight mutation shouldn't be persisted and replayed.The fix dispatches
continueright beforeretryer.start()when the mutation is still marked paused but can start now, the same dispatch #9015 added for restored mutations. It readsthis.state.isPaused, so a restored mutation that was already continued doesn't get a second one.Tests in
mutation.test.tsx:onMutateruns is unpaused once it starts. On main it staysisPaused: true.onMutateresolves before its turn stays paused. It passes on main and fails if the fix unpauses too early.✅ Checklist
pnpm run test:pr, or these tests do not apply to this pull request.🚀 Release Impact
Summary by CodeRabbit
onMutateis still resolving now resume correctly. Mutations waiting for connectivity can proceed once they are able to run, while mutations queued behind another mutation remain paused until the preceding mutation finishes. This keeps mutation execution aligned with availability and queue order and prevents eligible mutations from remaining paused or executing more than once.