Uh oh!
There was an error while loading. Please reload this page.
fix(query-core): release the retryer once a fetch settles - #11163
Conversation
A query kept its last retryer for life, and the settled promise holds that fetch's raw result: a second full copy of the data once a refetch has been structurally shared into state.data, and still held after reset() or removal.
📝 WalkthroughWalkthrough
ChangesSettled retryer release
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
View your CI Pipeline Execution ↗ for commit a4234c2
☁️ Nx Cloud last updated this comment at |
Uh oh!
There was an error while loading. Please reload this page.
* fix(query-core): release the retryer once a mutation settles Mutation.execute() never cleared #retryer after settling, so the settled retryer's promise kept that mutation's result, variables and context reachable for as long as the MutationCache retained the Mutation. Mirror the treatment Query.fetch() received in #11163, guarded by an identity check so a mutation re-executed from a cache callback keeps its own retryer. Releasing the retryer alone would change continue(): a settled mutation no longer has a retryer to continue, so it would fall through to execute() and run the mutationFn a second time. Both internal callers filter on state.isPaused and never reach a settled mutation, but continue() is reachable directly, so the fallback is now gated on the mutation still being pending -- the same condition execute() already uses to detect a restored mutation. Fixes#11216 * test(query-core): assert the settled retryer is actually released The previous tests only guarded the continue() gating and passed on main too, so they did not demonstrate the fix. continue() is the only reader of #retryer outside execute(): while a settled retryer is still held it hands back that retryer's promise, which resolves with the raw result it closed over (or rejects with its error). Both new tests fail on main and pass with the retryer released. --------- Co-authored-by: Dominik Dorfmeister 🔮 <office@dorfmeister.cc>
🎯 Changes
Query.fetch()leaves#retryerset after the fetch settles. The retryer's resolved promise still holds the raw result of that fetch, so once a query has refetched it holds its data twice: the structurally shared objects instate.data, plus the fresh result the promise resolved with. It also meansreset()andremoveQueries()don't free the data while anything still points at the query.This clears
#retryerin the existingfinallyonce the fetch has settled. The identity check is there so a fetch started synchronously from a cacheonSuccess/onSettledcallback keeps its own retryer. The other readers of#retryerare already behind?.or afetchStatuscheck, so the only visible change is thatquery.promiseisundefinedafter a fetch has settled instead of the settled promise.✅ Checklist
pnpm run test:pr.🚀 Release Impact
Summary by CodeRabbit
Bug Fixes
Release