0

I am building a real-time application using React, Apollo and GraphQL. My plan was that a component will issue a query and then subsequently depend on subscriptions to keep the client cache consistent with backend data in real time. However, I don't believe this will work because I will have to unsubscribe from the subscription when the component is unmounted. When the component is mounted again, the results will be fetched from the query cache and so they will actually be out of date because all the changes that happened in between will be missed since subscription was off. Also turning on the subscription again will mean that the results will get messed up since the changes have been missed in between.

For e.g., in component A, if I have a query:-

query {
  customers {
    id
    name
    phoneNo
  }
}

and a subscription:-

subscription customersUpdated {
  customersUpdated {
    id
    name
    phoneNo
  }
}

The customers query runs when A gets mounted for the first time. The results are cached. All changes to customers data are recorded with the help of subscription customersUpdated. Note that the subscription doesn't return all customers but just the changes that need to be merged into the query cache. When A is unmounted, I unsubscribe from the subscription. Let's say 5 changes are made to the customers data by another user while A stays unmounted for our current user. When A is mounted again, those 5 changes have been missed and the query just fetches results from the cache. The subscription starts again but now the data is in a bad state since we have missed those 5 changes and won't get them ever!

What is the correct pattern for using subscriptions here? I am trying to avoid time based refetching using the query since I want the application to work in real time. Also in real time, I just want to pull the changes instead of pulling all the data unnecessarily.

Nikhil Agarwal
  • 529
  • 1
  • 4
  • 16
  • You could try apollo-link-firebase https://github.com/Canner/apollo-link-firebase. It supports real-time subscription using apollo-link and firebase client js sdk. – williamC Mar 27 '18 at 10:09

1 Answers1

1

There are a few things you can do:

  1. Simply use the network-only or cache-and-network fetch policy on your GraphQL queries, so that you get up to date data when your component mounts. Initialize the subscription as usual.
  2. Don't stop the subscription when the component unmounts, and handle your subscription lifecycle outside of the components. This might be more work but then you can have control over when it starts and stops.

However, I would encourage you to think more about which parts of your app actually need to be realtime. In most apps, only a small part of the experience needs to have low-latency data updates, so it might be a better strategy to use subscriptions only in small cases. At the end of the day it's often easier to reason about the scaling of a stateless architecture.

stubailo
  • 6,077
  • 1
  • 26
  • 32
  • I wanted to do something like firebase where everything is realtime and all data is sent over the socket. I will have to figure out what approach I should take now. Thanks for the options! One more concern with subscriptions is that it looks like each subscription opens a new connection with the server which means server might have to handle way too much load. Couldn't it all be done over just one socket connection? – Nikhil Agarwal Jun 27 '17 at 05:57
  • 1
    All of the subscriptions are run over one connection, does something make it look like there's a new connection for each one? And yeah, if you want something that works like Firebase then Firebase is the best option - GraphQL doesn't have the same set of features. You could also try Meteor if you want an open source solution where everything is realtime. – stubailo Jun 27 '17 at 13:12
  • How about using gun js with graphql for building a real-time offline first application? I will check the connection problem again. I got an error which seemed to indicate multiple connections. – Nikhil Agarwal Jun 28 '17 at 01:19