Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EventEmitter Memory Leak in Event Broker #351

Closed
wooliet opened this issue Jun 30, 2017 · 4 comments
Closed

EventEmitter Memory Leak in Event Broker #351

wooliet opened this issue Jun 30, 2017 · 4 comments

Comments

@wooliet
Copy link
Contributor

wooliet commented Jun 30, 2017

Issue

For every subscription created over the same socket, a "close" event handler is added to the same socket instance. After 11 subscriptions, this triggers Node's warning of a possible memory leak.

Source

lib/event_broker.js
https://github.com/zettajs/zetta/blob/master/lib/event_broker.js#L125

client.once('close', function() {
  unsubscribe();
});

Steps to Reproduce:

  1. Run an instance of zetta
  2. Connect to /events
  3. Create 11 subscriptions over the same socket
var zetta = require('zetta');
zetta()
 .name('test')
 .listen(3000);
> wscat -c "http://localhost:3000/events"

> {"type":"subscribe", "topic":"**"}
< {"type":"subscribe-ack","timestamp":1498851155023,"topic":"**","subscriptionId":1}

.....


> {"type":"subscribe", "topic":"**"}
< {"type":"subscribe-ack","timestamp":1498851172264,"topic":"**","subscriptionId":11}

(node:7108) Warning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit

@wooliet
Copy link
Contributor Author

wooliet commented Jun 30, 2017

It looks like you might be able to just remove the block of code at line 125. There is already a "close" event handler that runs through all of the saved unsubscribe functions.

Welp, that was wrong.

https://github.com/zettajs/zetta/blob/master/lib/event_broker.js#L322

  // Unsubscribe to all subscriptions if the client disconnects
  client.on('close', function() {
    Object.keys(unsubscriptions).forEach(function(subscriptionId) {
      unsubscriptions[subscriptionId].forEach(function(unsubscribe) {
        unsubscribe();
      });
      delete unsubscriptions[subscriptionId];
    })
  });

@wooliet
Copy link
Contributor Author

wooliet commented Jun 30, 2017

@kevinswiber or @AdamMagaluk Any insights? I'm not sure what's going on in this unit test that causes a failure (https://travis-ci.org/zettajs/zetta/jobs/248924395). From what I can tell, the created unsubscribe function is called as part of the unsubscriptions collection on "close" and "unsubscribe" events.

I don't understand what the additional "close" handler added on each subscription is accomplishing (and why the unit test fails when it's removed).

@wooliet
Copy link
Contributor Author

wooliet commented Jun 30, 2017

I've got it. What I was missing was the difference between streamEnabled clients and those that are not streamEnabled. PR on its way.

Having this fixed is important because we've got a custom Node Red node for creating topic subscriptions. Underneath it is a single, long-lived socket connection over which subscriptions are managed. New nodes, simple UI changes of existing nodes, updating topics of existing nodes, etc. will ALL cause subscriptions over the socket.

Eventually the number of "close" event listeners added to the client would get out of control.

@AdamMagaluk
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants