Tips on ending socket connection for GraphQL subscription with Apollo

I need to handle closing GraphQL Subscriptions on my Apollo server when a user logs out. Should I close the socket connections on the client side or in the backend?

In my Angular front-end with Apollo Client, I manage GraphQL subscriptions by extending the Subscription class from apollo-angular. To close subscription channels, I use the typical takeUntil rxjs implementation:

this.userSubscription
  .subscribe()
  .pipe(takeUntil(this.subscriptionDestroyed$))
  .subscribe(
    ({ data }) => {
      // logic goes here
    },
    (error) => {
      // error handling
   }
);
  

However, this method does not close the websocket on the server, potentially causing a subscription memory leak.

The setup of Apollo Server (and express) for subscriptions includes:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  subscriptions: {
    onConnect: (connectionParams, webSocket, context) => {
      console.log('on connect');
      const payload = getAuthPayload(connectionParams.accessToken);
      if (payload instanceof Error) {
        webSocket.close();
      }
      return { user: payload };
    },
    onDisconnect: (webSocket, context) => {
      console.log('on Disconnect');
    }
  },
  context: ({ req, res, connection }) => {
    if (connection) {
      // set up context for subscriptions...
    } else {
      // set up context for Queries, Mutations...
    }

Whenever a new GraphQL subscription is registered by the client, I see console.log('on connect'); in the server logs, but console.log('on Disconnect'); is never triggered unless I close the front-end application entirely.

I haven't found any examples on how to close the websocket for subscriptions using Apollo. My primary goal is to implement Logout successfully. Am I overlooking something? Thank you in advance!

Answer №1

I found the solution for my issue after consulting this insightful discussion post

To establish a subscription using sockets, we utilized subscriptions-transport-ws

export const webSocketClient: SubscriptionClient = new 
SubscriptionClient(
  `${environment.WS_BASE_URL}/graphql`,
  {
    reconnect: true,
    lazy: true,
    inactivityTimeout: 3000,
    connectionParams: () => ({
      params: getParams()
    })
  }
);

In order to gracefully handle logout situations by unsubscribing from all channels and closing the subscription socket connection, we incorporated the webSocketClient SubscriptionClient within the logout function as follows:

webSocketClient.unsubscribeAll();
webSocketClient.close();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The mongoose library is not throwing any errors, indicating that the database connection has been established successfully

There are no errors in my code and it's a simple mongoose query - const posts = await Post.find(); console.log(posts); res.status(200).json({ status: 'success', results: posts.length, data: { ...

Tips for eliminating flicker upon the initial loading of a webpage caused by dynamic changes in CSS styles through JavaScript

Struggling with the load order of my CSS and JavaScript... Currently, I have a div with a blue background that is styled to appear sliced diagonally. However, upon initial page load (or CTRL+SHIFT+R), there's a brief moment where the slice effect doe ...

Sorting files in jquery file upload

Has anyone had experience using the jQuery-File-Upload library from https://github.com/blueimp/jQuery-File-Upload? I'm currently facing an issue and wondering if anyone could assist me in sorting the files in a different manner. By default, this scrip ...

Display PickerIOS when a button is clicked in a React Native application

I am a beginner with the react framework and I'm trying to implement a PickerIOS component on button click. However, I'm having trouble understanding how to call other classes upon an event. I found this code snippet on the React Native site: v ...

Changing a 64-bit Steam ID to a 32-bit account ID

Is there a way to convert a 64-bit Steam ID to a 32-bit account ID in Node.js? According to Steam, you should take the first 32 bits of the number, but how exactly can this be done in Node? Would using BigNumber be necessary to handle the 64-bit integer? ...

The app engine deployment is not implementing gzip compression on my content

Update Status An update is expected to be rolled out by the end of this month. I recently deployed a few websites on Google App Engine using standard environment NodeJS. It's been a bit delayed, but I'm hoping it's just something I overloo ...

Choosing a random element in React: A step-by-step guide

I'm currently working on a dynamic website that aims to load a random header component upon each refresh. Despite my various attempts, the functionality operates smoothly during the initial load but consistently throws this error on subsequent refresh ...

"Implementing form validation, utilize JavaScript to dynamically insert an unordered list containing list items (li) into a specified div

When validating a login form, I encountered a challenge with displaying errors using an unordered list for each validation error such as an incorrect username or email format. I am familiar with input validation but struggling with incorporating an unorder ...

Mongoose: efficiently fetching the query response

How are you doing? I'm just starting to learn about mongoose and mongoDB, and I'm encountering some issues with a basic query. Here is the code snippet in question: function addVoterToElection(req, res) { let query = Election.findOne({ &apos ...

Sort through data based on specific data fields upon the button click event using JSON and Vue.js

Is there a way to use JSON files in Vue.js to filter data based on category when a button is pressed? I have objects with categories inside the data. portfolio-v1.json { "data":[ { "image_path":"static/products/DEL ...

When attempting to import the OrbitControls.js file, Three.js encounters an error and fails

I am completely new to javascript and unfamiliar with working with libraries. I am currently experimenting with basic three.js code, but unfortunately facing issues that I cannot seem to resolve. Following the documentation on Threejs.org, I have set up a ...

When cascading, $q.All did not wait for all promises to finish

Working with $q.all to execute an array of promises asynchronously has been my recent task. I encountered a situation where I needed to ensure that one of the elements in the array completes its promise execution before moving on to the outermost 'the ...

'view' is not recognized as a valid property of the 'div' element in Ionic3, so it cannot be bound

I am a beginner with Ionic and I'm trying to incorporate Angular Calendar into my Ionic3 application. However, I am encountering an error that says, "Can't bind to 'view' since it isn't a known property of 'div'. Here&ap ...

The authentication process in ExpressJS with Passport.js is failing to return the res.user object in React

I recently followed a tutorial on Medium about implementing Passport js with a MERN stack. While I was successful in getting authentication to work, I am facing challenges with persisting users between routes. Below are excerpts from the code I used: ...

Customizing MUI DataGrid: Implementing unique event listeners like `rowDragStart` or `rowDragOver`

Looking to enhance MUI DataGrid's functionality by adding custom event listeners like rowDragStart or rowDragOver? Unfortunately, DataGrid doesn't have predefined props for these specific events. To learn more, check out the official documentati ...

Delay the processing of incoming HTTP requests in Node.js

Intentionally maintaining a broad scope here because I have a feeling I might be overlooking a key concept. Working with a Node/Express server, my goal is for the server to serve as a throttle by storing incoming http requests (either in memory or a separ ...

JS - Add a key to corresponding values in arrays and objects

I'm looking to populate objects in array1 with key values from other objects in array2. This involves matching corresponding values in both arrays and pushing the correct key. let array1 = [ { "Ref": "28189-060-B", "Otherkey": "Whatever" ...

Ensuring that hover remains active despite mousedown in JavaScript, CSS, and HTML

It appears that in browser-javascript hover events are deactivated when the mouse button is pressed down, as demonstrated by the following example: (Please run the code snippet to witness what I am referring to.) * { user-select: none; } #click, #drag, ...

Is there a way to seamlessly roll the camera using a button in ThreeJS alongside TrackballControls without causing any conflicts?

When working with ThreeJS, I encountered an issue with rotating the camera using a button. Here is the code snippet I used: camera = new THREE.PerspectiveCamera(...) function roll(angle) { const quaternion = new THREE.Quaternion(); const lookat = ...

stream a song with a font awesome symbol

Can an audio track be played using a font awesome icon, such as displaying the song name (mp3) with a play icon right next to it? When users click on the play icon, can the track start playing and be paused or stopped at will? The list will consist of app ...