-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
"Store reset while query was in flight(not completed in link chain)" when stopQuery is called right after resetStore. Race condition? #3766
Comments
Thanks for the detailed issue report @nyanpasu. If you're interested in submitting a PR to help address this, that would be awesome! |
Hi, will this issue be resolved soon? Is there a workaround? |
caught apollo issue UI related: apollographql/apollo-client#3766
I just ran into this same problem but from a slightly different angle. The promise returned by |
I'm also seeing this problem. Any fix yet? It definitely seems to be a race condition - if I add a timeout between logout and resetStore then this error goes away. It seems like as long as there's one more render between the logout and the resetStore then the error goes away. This is for an |
I try this and it worked for me : |
Did you also follow the other steps here to reproduce the issue?
|
I wonder if someone could verify whether this is a good minimal reproduction of this bug? https://codesandbox.io/s/rj3w4vm4xo The significant bit: componentDidMount() {
console.log('resetStore 1: start');
this.props.client.resetStore()
.then(() => console.log('resetStore 1: done'))
.catch(e => {
console.error('resetStore 1: failed', e);
});
setTimeout(() => {
console.log('calling setState');
// this removes the <Query/> from render and triggers its fetch to be cancelled
this.setState({ shouldShowQuery: false }, () => {
console.log('setState callback');
console.log('resetStore 2: start');
setTimeout(() => this.props.client
.resetStore()
.then(() => console.log('resetStore 2: done'))
.catch(e => console.error('resetStore 2: failed', e))
, 1000
);
});
});
} It doesn't seem to matter how long the timeout is, whenever the 2nd |
@nyanpasu I couldn't quite reproduce the bug using your flow of
https://codesandbox.io/s/nnv997ply0 Output:
Would you have time to take a look and see what I'm missing? |
My bad, wasn't expecting "should fix ###" to close the issue |
Thanks for reporting this. There hasn't been any activity here in quite some time, so we'll close this issue for now. If this is still a problem (using a modern version of Apollo Client), please let us know. Thanks! |
Can confirm this is still an issue |
If somebody has still this issue... I resolved it with
|
I used this but it seems only worked in "current session of apollo". Which means that if I am doing the code like below, when I refresh the app I get the previous Apollo client state without the "clearing" thing. So User is still signed in even thought my auth headers have been cleared and signOut mutation completed successfully. This is my AuthNavigator: //other code...
//using lazy query for getting currentUser
const [
getUserMe,
{loading: loadingUserMe, error: errorUserMe, data: dataUserMe, client}
] = useLazyQuery(QUERY_USER_ME);
let _queryCompleted = false;
//other code...
//handler called after calling signOut mutation
signedOut: async () => {
await AsyncStorage.multiRemove([
'access-token',
'client',
'token-type',
'expiry',
'uid'
]).then(() => {
if (client) {
console.log('can clean Apollo cache');
client.stop();
client.clearStore().then((_) => {
console.log('Apollo cache cleared');
setAuthState((prev) => ({...prev, isSignout: true, userMe: null}));
console.log(
'AuthNavigator got signedOut, so cleared auth headers and cache and we show signIn screen'
);
});
}
});
},
///...other code
useEffect(() => {
const bootstrapAsync = async () => {
console.log('AuthNavigator called userMe');
getUserMe();
};
bootstrapAsync();
}, []);
if (dataUserMe && !_queryCompleted) {
console.log('AuthNavigator got userMeData', dataUserMe);
authState.userMe = dataUserMe.me;
authState.isLoading = false;
_queryCompleted = true;
}
///...other code Is there a way to kind "write" the clearing happened with client.clearStore()? 🙏🏻 |
@azuxx to clear the store when signing out, try these two:
Also, using |
@chris-guidry Thank you for your suggestion, I am using hooks and useLazyQuery so I tried like this with your suggestion but it does not work. Did the logout flow correctly, then I refreshed the app but there is still the logged user :( signedOut: async () => {
await AsyncStorage.multiRemove([
'access-token',
'client',
'token-type',
'expiry',
'uid'
]);
if (client) {
console.log('can clean Apollo cache');
await client.cache.reset();
await client.resetStore();
}
setAuthState((prev) => ({...prev, isSignout: true, userMe: null}));
console.log(
'AuthNavigator got signedOut, so cleared auth headers and cache and we show signIn screen'
);
} |
@chris-guidry Fixed! It was also a server issue🤦🏻♂️ |
I don't understand how this issue is closed while it is still there and happening. |
Currently, queries are getting stuck in the
QueryManager.fetchQueryPromises
Map whenstopQuery
is called while that query is in flight.Inside
QueryManager.fetchQuery
a subscription is added to theQueryInfo
(QueryManager.query
object) of the Observable representing the current request.On the subscription, callbacks are set up to remove the
queryId
fromQueryManager.fetchQueryPromises
When
stopQuery()
is called before this query resolves, the promise will stay in that map because the subscription has been removed, therefore the callbacks to remove it will no long trigger.Later on, this will cause problems when one tries to call
resetStore()
Intended outcome:
I think queries should be removed from that Map after subscriptions get removed.
So as a solution, I might suggest that as part of the clean up for stopQuery, that the
requestId
should be removed fromQueryManager.fetchQueryPromises
. Perhaps there is a cancel method to evoke, or I should reject the promise with a new Error that the query has been cancelled.Actual outcome:
Queries are staying in that Map.
How to reproduce the issue:
It's an edge case, but this is how I ran into this issue through react-apollo:
resetStore()
via user interactionVersions
In hindsight I should have just written a PR instead.
The text was updated successfully, but these errors were encountered: