{{ message }}
Repository navigation
Conversation
… disposed After TanStack#9810, a query created inside $effect.root with an explicit QueryClient stays subscribed after the root's disposer runs: interval refetches continue, and a pending request's AbortSignal is never aborted. The eager observer.subscribe() from the async-Svelte rework only had onDestroy() for teardown, which does not run in non-component effect roots; when the client/restoration subscription never changes, watchChanges never resubscribes either, so nothing ever unsubscribes. Register the teardown with the enclosing effect root's disposal as well (via runEffect, now exported), keeping onDestroy for the server and component paths. Component unmount behavior is unchanged; double unsubscribe is a no-op. Regression test by @Osraka from the issue's linked branch. Fixes TanStack#11587
Contributor
Collaborator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Fixes #11587 — after #9810, a query created inside
$effect.rootwith an explicitQueryClientremains subscribed after the root's disposer runs: interval refetches continue, and a pending request consuming itsAbortSignalis never aborted.Root cause
#9810 replaced the
$effect(() => { return unsubscribe })form with an eagerobserver.subscribe(...)(needed for server and suspended branches) pluswatchChangesfor resubscription, and madeonDestroythe only teardown. But:onDestroydoes not run in non-component$effect.rootcontexts (the surroundingtry/catchswallows the failure), andwatchChangesnever resubscribes — its first run registers no cleanup,so in an
$effect.rootnothing ever unsubscribes the eager subscription. Component unmount is unaffected becauseonDestroyworks there.Fix
Register the teardown with the enclosing effect root's disposal as well —
runEffect('pre', () => () => unsubscribe())— keepingonDestroyfor the server path ($effect.predoes not run during SSR) and components.runEffectis now exported fromutils.svelte.ts. Callingunsubscribetwice is a no-op, so the component path is unchanged.Verification
main— 10 failed, 2 passed (observer count stays 1, cache entry survivesgcTime, pending request not aborted, interval refetches continue).@tanstack/svelte-querysuite: 24 files / 226 tests, all pass (includes the new file).svelte-check: identical 4 errors / 48 warnings before and after (pre-existing tooling issues:root.eslint.config.jsmodule resolution andRegExp.configtypes, both in untouched files); ESLint on changed files: 0 errors; changeset included.The regression test is @Osraka's, from the branch linked in the issue.
Summary by CodeRabbit