Search code examples
reactjsgraphqlapollo-clientgraphql-subscriptions

How to detect disconnect and reconnect for subscription(websocket) in apollo client


I am building a chat service and I want to handle the cases when the subscription(websocket) connection is disconnected. Apollo client is configured like bellow. I removed unnecessary code like cache, authLink etc.

How do I do this with react, apollo client? If its disconnected, I would like to show that to the chat page and when the user reconnects, I would like to fetch all the missed chat messages. This is why I need to know the disconnect, connect events

Below are the relevant packages used in this app:

"@apollo/client": "^3.3.7",
"subscriptions-transport-ws": "^0.9.18",
"react": "^17.0.1"
const httpLink = new BatchHttpLink({ uri: config.API_URL })
const wsLink = new WebSocketLink({
  uri: config.WS_URL,
  options: {
    reconnect: true,
    connectionParams:{       
      authToken: accessToken,
    },
  },
})

const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query) 
    return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'
  },
  wsLink,
  httpLink
)
const client = new ApolloClient({
  cache,
  link: from([new SentryLink(), authLink, errorLink, splitLink]),
})

Solution

  • I finally found the solution. It turns out that you can declare a SubscriptionClient first and then insert this into WebSocketLink, rather than declare with WebSocketLink directly.

    With SubscriptionClient, you can listen to the necessary events, whereas with WebsocketLink its not really possible(or very limited).

    Unfortunately, no where in Apollo docs, mentions SubscriptionClient or ways of handling connection issues.

    import { WebSocketLink } from '@apollo/client/link/ws'
    import { SubscriptionClient } from 'subscriptions-transport-ws' // <- import this
    
    const wsClient = new SubscriptionClient(config.WS_URL, {
      reconnect: true,
      connectionParams: {
        authToken: accessToken,
      },
    })
    
    const wsLink = new WebSocketLink(wsClient)
    

    By doing so, now you can listen to connection events with wsClient

    wsClient.onConnected(() => console.log("websocket connected!!"))
    wsClient.onDisconnected(() => console.log("websocket disconnected!!"))
    wsClient.onReconnected(() => console.log("websocket reconnected!!"))
    

    There are more events you can listen to. But these events are sufficient to implement fetching missed chat messages.

    With these events, after initial connection, you can store the disconnectTimestamp on disconnect event. When you receive onReconnected event, you can simply fetch chat messages that were created after the disconnectTimestamp