-
Notifications
You must be signed in to change notification settings - Fork 786
Never fetch recycled queries on network interface #531
Conversation
@jacobk: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Meteor Contributor Agreement here: https://contribute.meteor.com/ |
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.
Looks great 👍
I’d just like to see a few changes to increase test completeness 😊
src/graphql.tsx
Outdated
@@ -636,6 +636,9 @@ class ObservableQueryRecycler { | |||
// Stop the query from polling when we recycle. Polling may resume when we | |||
// reuse it and call `setOptions`. | |||
observableQuery.stopPolling(); | |||
observableQuery.setOptions({ | |||
fetchPolicy: 'cache-only', |
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’s remove stopPolling
for pollInterval: 0
in setOptions
. It does the same thing: https://github.com/apollographql/apollo-client/blob/1e986c57e12d98f2831616005ef0211d4c9689d1/src/core/ObservableQuery.ts#L307-L311
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.
Fixed
</ApolloProvider> | ||
); | ||
|
||
expect(Object.keys((client as any).queryManager.observableQueries)).toEqual(['1']); |
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.
Could we check that this observable query still exists after we unmount as well?
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.
Fixed
client.resetStore(); | ||
|
||
// The query should only have been invoked when first mounting and not when resetting store | ||
expect(networkInterface.query).toHaveBeenCalledTimes(1); |
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’s also check that this method was called once before we unmounted.
You should also duplicate this test and assert that query is called twice if we do not unmount, but we still call resetStore
.
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.
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 thought of another edge case.
@@ -635,7 +635,10 @@ class ObservableQueryRecycler { | |||
public recycle (observableQuery: ObservableQuery<any>): void { | |||
// Stop the query from polling when we recycle. Polling may resume when we | |||
// reuse it and call `setOptions`. | |||
observableQuery.stopPolling(); | |||
observableQuery.setOptions({ | |||
fetchPolicy: 'cache-only', |
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.
On second thought, I’m not ready to merge this because if an observable query gets reused the fetchPolicy
will stay as cache-only
which is undesirable. Could you write a test to show this doesn’t happen? If it does could you make sure it does not?
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 think the solution is to update line 672 so that it sets the default fetch policy if no other fetch policy was found. So:
observableQuery.setOptions({
...options,
fetchPolicy: options.fetchPolicy || 'xyz',
});
Where 'xyz'
is the default fetchPolicy
. This should guarantee that the cache-only
policy is reset.
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.
Sure!
I thought that setOptions
where strictly overriding the old options but I just noticed that it doesn't. As far as I can tell there's no explicit default for fetchPolicy
and the current setOptions
implementation doesn't allow removing previously set properties:
const oldOptions = this.options;
this.options = {
...this.options,
...opts,
} as WatchQueryOptions;
Ideally I'd like to remove both the pollInterval
and fetchPolicy
completely before applying options
inside reuse
.
Any ideas? I'll commit the new breaking test case for now (which is testing for strict equality of options before and after recycle).
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 pushed a possible fix for reverting the options changed when recycling. IMHO it's a little on the hacky side since I need to manually overwrite the ObservableQuery
's options to fully remove the altered options.
Maybe setOptions
should be updated to allow for options to be removed completely?
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’s try instead saving the old options in recycle()
and then merging those options with the new options in reuse()
. Do you think that would work?
But perhaps this isn’t the right thing to do at all. Perhaps what we really need to do is create some kind of light-weight subscribe in apollo-client
that will only allow receiving updateQueries
and refetchQueries
instead of writing workarounds in the recycler…
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.
The issue with merging options is that you cannot remove any - only update and add. I think fetchPolicy
is omitted by default. Maybe it's enough to set it to undefined
instead? But then it's a less straight forward procedure to store the old options and later restore them if the values needs to be reasoned about.
But if it's a sound approach to simply override the observableQ.options
before calling setOptions
(like I do now, that could be done with the snapshotted options too of course).
I haven't studied the whole thing to fully reason about the recycler. However, the current issue with fetchPolicy
and refetching onresetStore
is giving us real trouble. Given the issue at hand the limitations of apollo-client
's setOptions
are my only concern.
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.
Setting to undefined
should be the equivalent of removing. Does this make the implementation easier?
I don’t like the idea of setting options
manually mainly because we haven’t yet considered all of the implications 😣
The last commit sets the altered options to |
@calebmer happy with last version or do you have doubts about this approach? |
Thanks @jacobk! I'm away for the weekend, but I'll take a look on Monday. 🙂 |
Great, thanks! |
Thanks @jacobk, I think this looks good now, and it might fix the |
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.
ship it.
See discussion in apollographql/apollo-client#1319