-
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
don't cancel existing subscriptions when updating cache from another source #10597
Conversation
🦋 Changeset detectedLatest commit: 84686b8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
✅ Deploy Preview for apollo-client-docs ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
This could also have some overlap with #10614, so I'm mentioning that here so I don't forget to take a look at that in this context. |
c1e7b79
to
9fff05a
Compare
b: "", | ||
}, | ||
}, | ||
// TODO: this should be `true`, but that seems to be a separate bug! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like invalid behavior to me, but also is an "independent" bug.
I will try to handle this in a separate pull request.
// there is just no way we can synchronously get the *right* value here, | ||
// so we will assume `true`, which is the behaviour before the bug fix in | ||
// #10597. This means that bug is not fixed in that case, and is probably | ||
// un-fixable with reasonable effort for the edge case of @export as | ||
// directives. | ||
containsDataFromLink = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just the unfortunate truth - we need this information synchronously to act on it, and there is no way we can do that. So this PR has to exclude fixing that.
I managed to get this PR "out of the Concast", to have much more local impact - and less bundle size. As a result, some internal functions now return a tuple instead of a single value, but that seemed to be the "least impact" solution here. @benjamn could you please take another look? |
src/core/QueryManager.ts
Outdated
networkStatus: NetworkStatus, | ||
): ConcastSourcesArray<ApolloQueryResult<TData>> { | ||
networkStatus: NetworkStatus | ||
): [containsDataFromLink: boolean, ...sources: ConcastSourcesArray<ApolloQueryResult<TData>>] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very glad to see we can keep this logic out of the Concast
implementation, but I'm a little uneasy with combining distinct pieces of information into one tuple array, especially when one of those items is also an array (sources
), and the other item is an unnamed boolean value (containsDataFromLink
).
For readability and maintainability (like adding more info properties in the future), I think I would prefer returning an object with named properties instead of a tuple, even though this is private code that we fully control.
However, I do appreciate why a tuple might minify better than an object with named properties, so I did a quick investigation to see how much bundle size would be added by using objects instead of tuples. The object-based approach adds +172 bytes, still coming in under the current bundle size limit of 32.72KB, which I think is worth it for readability and simpler typing.
Since I've already done this experiment, rather than asking you to reproduce the results, I could just push my commit to this branch, if that's okay with you @phryneas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's the commit: 18cb2f3
src/core/QueryManager.ts
Outdated
return [false, resultsFromCache(diff, queryInfo.markReady())]; | ||
return { fromLink: false, sources: [resultsFromCache(diff, queryInfo.markReady())] }; | ||
} | ||
|
||
if (returnPartialData || shouldNotify) { | ||
return [true, resultsFromCache(diff), resultsFromLink()]; | ||
return { fromLink: true, sources: [resultsFromCache(diff), resultsFromLink()] }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally used a helper function here since I thought this repetitive code might be bad for bundle size, but it seems GZIP is able to compress the two repeated prefixes reasonably well:
return{fromLink:false,sources:[
return{fromLink:true,sources:[
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with the current state of this PR if you are, @phryneas!
@@ -1,41 +1,39 @@ | |||
import gql from 'graphql-tag'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the commit that formats this file somewhere in .git-blame-ignore-revs
? I didn't see at as part of this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is in here. But it's a good point, I'll have to rewrite history on this PR so it can be merged without squashing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a couple of minor points of feedback, but this PR looks good otherwise. Thanks for getting this fixed! Looks like it was a tricky one to figure out 😄
.changeset/swift-mails-search.md
Outdated
"@apollo/client": patch | ||
--- | ||
|
||
Fix a potential race condition between a link and parallel cache updates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix a potential race condition between a link and parallel cache updates | |
Fix a race condition where parallel cache updates from multiple queries would sometimes result in incorrect `data`. |
See if you like this a bit better. I think the "between a link" feels a bit too ambiguous, or at least I'm not sure it adequately describes the fix here. Seems like the "multiple queries" is important looking at your test. Feel free to tweak this a bit more, but just wanted something that might help a dev looking at our changelog understand what we fixed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reworded it to "Fix a bug where an incoming cache update could prevent future updates from the active link."
src/core/QueryManager.ts
Outdated
).then(fromVariables) | ||
: fromVariables(normalized.variables!) | ||
); | ||
let concast: Concast<ApolloQueryResult<TData>>, containsDataFromLink: boolean; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let concast: Concast<ApolloQueryResult<TData>>, containsDataFromLink: boolean; | |
let concast: Concast<ApolloQueryResult<TData>>, | |
containsDataFromLink: boolean; |
I know this seems petty, but I honestly searched for a while before I realized this variable was defined in the same line as concast
. For readability, could we put this on its own line to make it easier to see where this variable is created?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not petty, perfectly valid complaint :)
(cherry picked from commit 0a67647)
169840f
to
6ab5479
Compare
… from the active link. Co-authored-by: Ben Newman <ben@apollographql.com>
6ab5479
to
84686b8
Compare
@jerelmiller once you're happy with the wording, this is ready for the "Rebase and Merge" (we have one separate formatting commit) button :) |
Well, I didn't hear any complaints about the new wording, so I'm merging :) |
@phryneas whoops missed your ping. Sorry about that! It's good 😄 |
This PR fixes an issue first reproduced in #10587.
For an explanation of the bug, take a look at this commit (a test) (That test is not very visible in the overall diff since I reformatted the ObservableQuery test.)
Basically: when a cache update from another source was triggered, that other cache update discarded & unsubscribed the currently running Link - even if it only was reading from cache.
With this PR, concasts now contain an array of "descriptions", describing the actions they contain - a link request, an update from cache, or unknown.
This allows the logic in
reobserve
to only replace the current concast if the incoming data source was a link request - which should be a more sensible approach.Unfortunately, this adds about 100b of bundle size - but especially with long-running queries with
@defer
in the future I don't see a way around this fix.Checklist: