Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apollo subscriptions - handling WS disconnects with subscribeToMore

I've been looking for a way to handle web socket disconnects in my React app with Apollo subscriptions and have not found a way to do so. The other examples I see in the apollo documentation show the below method for catching a reconnect:

  const wsClient = process.browser ? new SubscriptionClient(WSendpoint, {
    reconnect: true,
  }) : null;

  const wsLink = process.browser ? new WebSocketLink(wsClient) : null;

  if (process.browser) {
    wsLink.subscriptionClient.on(
      'reconnected',
      () => {
        console.log('reconnected')
      },
    )
  }

There are two issues with the above method:

  1. is that is does not catch when the user disconnects from their internet (only from when the server restarts for whatever reason)
  2. that the reconnect is triggered outside of my React apps components.

What I would like to be able to do is to is reload my "chat" component if the user either disconnects from their internet or if my express server goes down for any reason. For this to happen I would need my chat component to completely reload which i'm not sure would be possible from outside my component tree.

Is there a method in the Query or Subscription Apollo components to be able to capture this event and handle it accordingly from the component?

like image 410
red house 87 Avatar asked Feb 19 '19 09:02

red house 87


People also ask

Do GraphQL subscriptions use WebSockets?

Subscriptions are a GraphQL feature allowing the server to send data to its clients when a specific event happens. Subscriptions are usually implemented with WebSockets, where the server holds a steady connection to the client.

Does Apollo client use WebSockets?

Instead, Apollo Client subscriptions most commonly communicate over WebSocket, via the graphql-ws library. As mentioned in Choosing a subscription protocol, some servers use an older library called subscriptions-transport-ws .

Does Apollo Federation support subscriptions?

This approach to data graph ownership can have a transformational effect on the way engineering teams work together to expose product-driven query and mutation operations in a GraphQL API, but out-of-the-box, Apollo Federation doesn't support subscription operations.

How do GraphQL subscriptions work?

GraphQL subscriptions are made majorly to listen to when data is created on the server, when a data is updated, when a data is deleted, and when a data is read via query. The event to emitted is dependent on what the dev wants. The events are pushed from the server to the subscribing clients.


2 Answers

You can use SubscriptionClient callbacks from subscriptions-transport-ws, like this:

const ws = require("ws");
const { SubscriptionClient } = require("subscriptions-transport-ws");
const { WebSocketLink } = require("apollo-link-ws");
const { ApolloClient } = require("apollo-client");
const { InMemoryCache } = require("apollo-cache-inmemory");

const subClient = new SubscriptionClient(
    'ws://localhost:4000/graphql',
    { reconnect: true },
    ws
);

subClient.onConnected(() => { console.log("onConnected") });
subClient.onReconnected(() => { console.log("onReconnected") });
subClient.onReconnecting(() => { console.log("onReconnecting") });
subClient.onDisconnected(() => { console.log("onDisconnected") });
subClient.onError(error => { console.log("onError", error.message) });

const wsLink = new WebSocketLink(subClient);

const client = new ApolloClient({
    link: wsLink,
    cache: new InMemoryCache()
});

I'm using this for Node.js, but it will probably work for React too.

like image 83
lpereira Avatar answered Nov 15 '22 18:11

lpereira


There are a few ways I can think of to handle these cases but none of them are a one-shot solution, each case needs to be handled independently.

  1. Setup a online/offline listener (ref)
  2. Setup an Apollo middleware to handle network errors from your server (ref)
  3. Create a variable in your store, isOnline for example, which can hold a global reference of your app's state. Whenever the above two methods trigger, you could update the value of isOnline
  4. Finally, to bundle all of it together. Create a react HOC which uses isOnline to handle the network state for each component. This can be used to handle network error messages, refresh components once network is restored.
like image 23
varun agarwal Avatar answered Nov 15 '22 20:11

varun agarwal