Подписки GraphQL: максимальное количество слушателей превысило предупреждение

Мы используем подписки GraphQL и pubsub для подписки на сообщения.

Когда происходит более 10 подписок, мы получаем предупреждение узла «MaxListenersExceededWarning: обнаружена возможная утечка памяти EventEmitter».

Можно ли поднять максимальное количество слушателей в классе pubsub?

Класс pubsub находится внутри отдельного модуля и выглядит так:

import { PubSub } from 'graphql-subscriptions';

const pubsub = new PubSub();

export { pubsub };

Сервер подписки выглядит так:

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,
};


person Locco0_0    schedule 03.05.2017    source источник


Ответы (3)


Я написал исходную реализацию пакета graphql-subscriptions, который вы используете, поэтому я могу предоставить здесь некоторый контекст.

Простая библиотека EventEmitter pubsub, включенная в graphql-subscriptions, предназначена только для демонстрационных целей. EventEmitters на самом деле не масштабируются до больших чисел, они находятся в памяти и будут работать только до тех пор, пока у вас есть не более одного сервера.

Всем, кто пытается запустить подписки GraphQL в производственной среде, я настоятельно рекомендую использовать другую систему, например Redis или MQTT через graphql-redis-subscriptions или graphql-mqtt-subscriptions. Преимущество этого заключается в том, что сервер GraphQL остается без состояния (кроме веб-сокетов) и, таким образом, легко масштабируется по горизонтали.

person helfer    schedule 04.05.2017
comment
...Я настоятельно рекомендую использовать другую систему... спасибо, я ценю информацию. - person Alexander; 02.09.2017
comment
Это действительно следует добавить в файл readme для подписки на graphql. Я не осознавал этого и уже пару месяцев запускаю настройку EventEmitter по умолчанию в продакшене! (и постоянно получали предупреждения об утечке памяти) - person mxstbr; 05.10.2017
comment
Я пошел дальше и отправил PR, чтобы добавить примечание об этом в файл readme пакета: github.com/apollographql/graphql-subscriptions/pull/110 - person mxstbr; 05.10.2017
comment
Один экземпляр node.js может обрабатывать до 65 000 подключений к веб-сокетам. Так что, если у меня небольшой сервис, который делает всего несколько K подключений, просто использование graphql-subscription с увеличением setMaxListeners должно подойти, верно? - person Sihoon Kim; 26.01.2021

Выяснилось, что вы можете изменить максимальное количество прослушивателей в эмиттере событий экземпляра pubsub, например:

import { PubSub } from 'graphql-subscriptions';

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

export { pubsub };

person Locco0_0    schedule 03.05.2017

ee является защищенным членом PubSub, поэтому установка его напрямую вызовет ошибки в проекте TypeScript. Однако вы можете передать EventEmitter с настроенным счетчиком MaxListener в конструктор PubSub:

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

const biggerEventEmitter = new EventEmitter();
biggerEventEmitter.setMaxListeners(30);
const pubSub = new PubSub({eventEmitter: biggerEventEmitter});
person Keith Gillette    schedule 21.11.2020
comment
Спасибо тебе за это. Это действительно помогло. - person PAT-O-MATION; 06.05.2021