-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
useSubscription hook fails to receive expected data if reusing Concast observer from unmounting useSubscription hooks under certain conditions #10695
Comments
Good point - I'll close this issue and link to it in that issue then. |
Hi @Hsifnus 👋 Your PR was just released in Edit: I'm seeing the same (old) behavior with the |
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Issue Description
In React, if the current
ApolloClient
has query deduplication enabled, and one component with an ongoinguseSubscription
hook that has yet to complete unmounts at the same time as another component using auseSubscription
hook with exactly the same document and variables as the first component's hook, then this recently mounted component's subscription will be unable to receive incoming data from the subscription endpoint.After digging through with inspector breakpoints what happens in the Apollo client source code during this interaction, I found that this sequence of events consistently occurs:
useSubscription
hook mounts and sets up itsConcast
observable viaApolloClient.subscribe
. ThisConcast
will always start out with exactly one source that is immediately consumed to establish a source subscription within theConcast
.useSubscription
hook mounts and sees the old subscription still using itsConcast
for same document and variables as the new subscription and therefore (under query deduplication) reuses thatConcast
within theApolloClient.subscribe
call used to set the observable state in the newuseSubscription
hook.Subscription
obtained earlier from subscribing to itsConcast
. Assuming that the old subscription was the only subscription linked to theConcast
at the time, theConcast
now completes and performs all of the associated cleanup logic... except for unsubscribing from its source subscription, which is deferred viasetTimeout
.Concast
observable from two steps back.this.latest
within aConcast
,this.latest
can remain null within the reusedConcast
if theConcast
had not received any source subscription values before the old hook unmount and in that case prevents the new subscription from immediately completing viaConcast.deliverLastMessage
.Concast
source observable triggered by the old hook unmounting now finalizes theConcast
's cleanup, indefinitely cutting off the new subscription hook from receiving any data through the reusedConcast
.Interestingly, the
error
handler of the currentConcast
implementation has this code comment:Under the current error and complete handler logic, when immediately subscribing another observer to the
Concast
after removing the last existing observer from theConcast
, the source subscription of theConcast
will always be unsubscribed oncesetTimeout
kicks in, which is contrary to what the above comment describes.So far, I have made a branch of my personal fork in an attempt to address this issue in the spirit of the above code comment by preserving the
Concast
subscription if a new observer subscribes to theConcast
right as the last existing observer unsubscribes and if the subscription is still open to begin with. It seems to fix theuseSubscription
issue mentioned here and appears to work well with existing tests in the repo, but whether it is the best approach to this general issue is a matter to be discussed here.Link to Reproduction
https://codesandbox.io/s/test-apollo-graphql-subscriptions-forked-sxst71?file=/src/index.js
Reproduction Steps
Normally, the subscription data should appear on the screen after a period of loading, regardless of whether "Component A" or "Component B" is shown.
The public subscription endpoint only publishes one value before completing, so reproducing the bug requires the user to click the "Click here to toggle" text before the current subscription hook receives that value. If done right, the displayed component's
useSubscription
hook will be indefinitely stuck in the loading state until the components are toggled again.The text was updated successfully, but these errors were encountered: