Apollo-client: synchronising queries and subscriptions

Created on 18 Aug 2017  路  10Comments  路  Source: apollographql/apollo-client

if you use a query over http and a corresponding subscription over ws then you can run into problems where the data changes just after the query data is obtained on the server eg if you do this on the server:

````
test: () => {
const result = {
root: 'root',
test: test++,
};
setTimeout(() =>
pubSub.publish(
'testChanged',
{
testChanged: {
root: 'root',
test: test++,
},
},
), 0);
return result;
},

````

you end up with stale data on the client - because the subscription doesnt catch the change.

I was just wondering whether you'd thought about this scenario...

I seem to have fixed it by doing everything over ws and not using http at all which I am assuming produces a query and subscription arriving at the server in a pre determined order. Otherwise I think you'd have to have logic on the client to make sure the subscription had been received before the query is sent..

Most helpful comment

Is it possible to get an Apollo contributor to speak to this-- if there is not an enforced order (subscription, then query), would you consider a pull request to add such? Are there known complications to doing so? Is using the full websocket transport currently a reliable way of ensuring that no new data is missed by the subscription?

All 10 comments

I have been creating the query, initializing the subscription, then doing a refetch to make sure no updates were lost inbetween the original query and the subscription creation.

Is it possible to get an Apollo contributor to speak to this-- if there is not an enforced order (subscription, then query), would you consider a pull request to add such? Are there known complications to doing so? Is using the full websocket transport currently a reliable way of ensuring that no new data is missed by the subscription?

@rationalthug FWIU even using a websocket is not foolproof because the browser can disconnect and reconnect behind the scenes when network connection is variable so messages can be missed. If this is true there really needs to be a mechanism like an incrementing id with each message (+ a heatbeat) so the client can know if it has missed a message.

@gilesbradshaw Yep. Just curious if something along those lines is under consideration already or if it is desirable for someone else to take a crack at it.

@rationalthug not as far as i am aware,,

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Apollo Client!

@gilesbradshaw I'm not sure I totally follow? Can you provide a reproduction or some more info about what is going wrong here?

As far as I am concerned, for my current use cases, everything works correctly.

I can't speak to other configurations, but using full a full web socket network interface, and react-apollo, results in a predictable ordering of messages, with subscription enabled React components sending subscription messages first, followed by query messages. This results in no dropped subscription messages during normal use. If the web socket connection itself closes for some reason, then all bets are off anyway and we just re-query and start the subscription again when conditions permit.

The question seems to be if this situation holds for hybrid interfaces as well, and, if not, if the client will have some built-in facilities for handling dropped subscription messages. If the subscribe/query operations are not ordered as above in this case, there would seem to be a possibility of getting a query result, but losing a subscription message in between that and the subscription becoming active.

But the more I think about it, the more it seems like this would be better as something an app handles itself by checking application specific auto-incrementing IDs or timestamps, and then triggering a re-query itself if necessary.

@jbaxleyiii this is just extracted from my code but I hope it indicates what I mean..

in schema I have a typ test:

const Test = ` type Test { _id: String! root: String test: Int } `;

and my query has a query called test
const rootQueryString = ` # get an array of nodes either by node or path test: Test `;
my resolver returns test and also increments it and publishes the change..

````
let test = 0;
const query = {
test: () => {
const result = {
node: 'root',
test: test++,
};
setTimeout(() =>
pubSub.publish(
'testChanged',
{
testChanged: {
node: 'root',
test: test++,
},
},
), 0);
return result;
},
};

````

I have a testChanged subscription:
const rootSubscriptionString = ` testChanged: Test `;

my subscription does
testChanged: { subscribe: withFilter( () => { return pubSub.asyncIterator('testChanged'); } ), },

So if I use a client to query the above with http and subscribe to it with websockets sometimes I will miss the update which occurs straight after the query and sometimes I won't .

This is because the order in which the query and subscription arrive at the server is non determinate because they come on different transports.

If however I use websockets for both it solves the problem - because there is a single transport ie a single pipe so the order that the subscription and query arrive at the server is always the same.

I hope that makes sense :)

To help provide a more clear separation between feature requests / discussions and bugs, and to help clean up the feature request / discussion backlog, Apollo Client feature requests / discussions are now being managed under the https://github.com/apollographql/apollo-feature-requests repository.

This feature request / discussion will be closed here, but anyone interested in migrating this issue to the new repository (to make sure it stays active), can click here to start the migration process. This manual migration process is intended to help identify which of the older feature requests are still considered to be of value to the community. Thanks!

Was this page helpful?
0 / 5 - 0 ratings