Skip to content

Duplicate socket.io events #490

@kingcody

Description

@kingcody

As pointed out to me by a user of this generator. When a socket.io connection is made and the socket is registered to the model's post('save') hook, there is no method to remove these listeners. As a side effect as connections continue to be made (reloads or new) the hook's event listener list grows proportionally. For him this is causing an unwanted amount of events to be fired off, and due to his modifications, redundant effects (don't know the details, doesn't affect the issue).

I've searched the documentation on mongoose and I don't believe you can remove middleware events, at least not easily?

With that "assumption" I've rewritten thing.socket.js to roughly be:

module.exports = function(socketio) {
  thing.schema.post('save', function (doc) {
    socketio.to('thing').emit('thing:save', doc);
  });
  thing.schema.post('remove', function (doc) {
    socketio.to('thing').emit('thing:remove', doc);
  });
};

Notice that I only export one function, and it receives socketio the socket.io server, not an individual socket. This is because I only bind to the pre save hook once at server startup, like so:

server/config/socketio.js

module.exports = function (socketio) {
  socketio.on('connection', function (socket) {
    socket.address = socket.handshake.address !== null ?
            socket.handshake.address.address + ':' + socket.handshake.address.port :
            process.env.DOMAIN;

    socket.connectedAt = new Date();

    // Call onDisconnect.
    socket.on('disconnect', function () {
      onDisconnect(socket);
    });

    // Call onConnect.
    onConnect(socket);
  });

  // Insert sockets below
  require('../api/thing/thing.socket')(socketio);
};

I use socket.io rooms to handle the different clients/listeners. Since rooms are managed by the socket.io server I added listeners for join and leave events from the client sockets:

// When the user connects.. perform this
function onConnect(socket) {
 ...
  socket.on('join', function(room) {
    socket.join(room);
  });

  socket.on('leave', function(room) {
    socket.leave(room);
  });
}

The client can then sync updates as usual and only needs to call socket.emit('join', modelName) when syncUpdates and call socket.emit('leave', modelName) when unsyncUpdates (in addition to the normal actions). This should have the added benefit of not sending events to clients that they are not subscribed to; instead of the client simply ignoring the events. Also, the server does not have a continually growing list of event listeners on a model's schema; which would most likely appear as a mem leak over time.

EDIT: typo

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions