GraphQL Subscriptions: Max Listeners Exceeded Warning
Asked Answered
F

3

15

We are using GraphQL Subscriptions and pubsub to subscribe to posts.

When more than 10 subscriptions occur we get the the node warning "MaxListenersExceededWarning: Possible EventEmitter memory leak detected."

Is it possible to raise the max listeners in the pubsub class?

The pubsub class is inside a separate module and looks like this:

import { PubSub } from 'graphql-subscriptions';

const pubsub = new PubSub();

export { pubsub };

The subscription server looks like this:

import { SubscriptionManager } from 'graphql-subscriptions';
import { createServer } from 'http';
import { SubscriptionServer } from 'subscriptions-transport-ws';

import { pubsub } from './subscriptions';
import executableSchema from './executableSchema';

const WS_PORT = 8080;

const websocketServer = createServer((request, response) => {
  response.writeHead(404);
  response.end();
});

websocketServer.listen(WS_PORT, () => console.log(
  `Websocket Server is now running on http://localhost:${WS_PORT}`
));

const subscriptionManager = new SubscriptionManager({
  schema: executableSchema,
  pubsub: pubsub,
  setupFunctions: {
        newPost: (options, args) => {
         return {
            newPostChannel: {
               filter: (post) => {
                  return args.publicationId === post.relatedPublication.id;
               }
            },
         };
      },
  },
});

const subscriptionServer = new SubscriptionServer({
  subscriptionManager: subscriptionManager
}, {
  server: websocketServer,
  path: '/',
});


export {
  subscriptionServer,
};
Florence answered 3/5, 2017 at 5:54 Comment(0)
H
17

I wrote the original implementation of the graphql-subscriptions package you're using, so I can provide some context here.

The simple EventEmitter pubsub library included in graphql-subscriptions is only intended for demo purposes. EventEmitters don't really scale to large numbers, they're in-memory, and they'll only work as long as you have no more than a single server.

For anyone trying to run GraphQL subscriptions in production, I strongly recommend using a different system, for example Redis or MQTT through graphql-redis-subscriptions or graphql-mqtt-subscriptions. This will have the advantage of keeping the GraphQL server stateless (apart from the websockets) and thus easy to scale horizontally.

Hypnos answered 4/5, 2017 at 18:38 Comment(4)
"...I strongly recommend using a different system..." thanks, I appreciate the info.Piderit
This should really be added to the graphql-subscriptions readme. I did not realise this and have been running the default EventEmitter setup in production for a couple of months now! (and have consistently been getting memory leak warnings)Gottfried
I went ahead and submitted a PR to add a note about this to the readme of the package: github.com/apollographql/graphql-subscriptions/pull/110Gottfried
A single node.js instance can handle up to about 65K websocket connections. So if mine is a small service that only makes few K connections, just using graphql-subscription with setMaxListeners increased should be fine, right?Eley
P
5

ee is a protected member of PubSub, so setting it directly will cause errors in a TypeScript project. However, you can pass an EventEmitter with an adjusted MaxListener count to the PubSub constructor:

import { PubSub } from 'apollo-server-express';
import { EventEmitter } from 'events';

const biggerEventEmitter = new EventEmitter();
biggerEventEmitter.setMaxListeners(30);
const pubSub = new PubSub({eventEmitter: biggerEventEmitter});
Phinney answered 21/11, 2020 at 15:41 Comment(1)
Thank you for this. It really helped.Halftimbered
F
4

Found out that you can change the max listeners in the event emitter of the pubsub instance, like so:

import { PubSub } from 'graphql-subscriptions';

const pubsub = new PubSub();
pubsub.ee.setMaxListeners(30); // raise max listeners in event emitter

export { pubsub };
Florence answered 3/5, 2017 at 15:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.