Skip to content
This repository has been archived by the owner on Apr 13, 2023. It is now read-only.

Never fetch recycled queries on network interface #531

Merged
merged 14 commits into from
Apr 7, 2017
Merged

Never fetch recycled queries on network interface #531

merged 14 commits into from
Apr 7, 2017

Conversation

jacobk
Copy link
Contributor

@jacobk jacobk commented Mar 13, 2017

@apollo-cla
Copy link

@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/

Copy link
Contributor

@calebmer calebmer left a 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',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

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']);
Copy link
Contributor

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?

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

@calebmer calebmer left a 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',
Copy link
Contributor

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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).

Copy link
Contributor Author

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?

Copy link
Contributor

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…

Copy link
Contributor Author

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.

Copy link
Contributor

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 😣

@jacobk
Copy link
Contributor Author

jacobk commented Mar 17, 2017

The last commit sets the altered options to undefined instead. I think this is symmetric enough compared to keeping a copy of the old options around and still do the same manual handling of the options that should be set to undefined if they weren't initially set.

@jacobk
Copy link
Contributor Author

jacobk commented Mar 27, 2017

@calebmer happy with last version or do you have doubts about this approach?

@jacobk
Copy link
Contributor Author

jacobk commented Apr 1, 2017

@helfer, any thoughts on this PR, anything else needs changing? (@calebmer asked me to poke you in is absence)

@helfer
Copy link
Contributor

helfer commented Apr 1, 2017

Thanks @jacobk! I'm away for the weekend, but I'll take a look on Monday. 🙂

@jacobk
Copy link
Contributor Author

jacobk commented Apr 1, 2017

Great, thanks!

@helfer
Copy link
Contributor

helfer commented Apr 7, 2017

Thanks @jacobk, I think this looks good now, and it might fix the resetStore issue, so I'll release a new patch version with this change before the weekend! 🙂

Copy link
Contributor

@helfer helfer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ship it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants