server sent events creates way too many listeners for single client
Asked Answered
G

1

0

I am using server sent events in MEAN stack. I am able to push data from server to client whenever required.

But one thing i noticed that even if i am the only client hitting the server. There are multiple listeners for me and events are broadcast to say 40 listeners(if i wait long enough for the client to reconnect 40 times).

Multiple listeners are also created when user reloads.

How can i limit the listeners to say 1 listener to per event per client. Is this even possible with server sent events.

I am trying to keep the connection open as long as the user is using the website and close only when the browser/tab is closed or clients request a reload.

NOTE : stream is an EventEmitter object which I use to pass events so that the required changes can be monitored and appropriate data can be send through server sent events.

const function = async (request: Request, response: Response) => {
    console.log("client connected to broadcasting channel")
    console.log("listeners : " , stream.listenerCount('event-L'))
    response.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        "X-Accel-Buffering": "no"
    });
    response.flushHeaders();

    stream.on('event-L', (event, data) => {
            console.log("Broadcasting event-L")
            response.write('event: ' + event + '\n' + 'data:' + JSON.stringify(data) + '\n\n')
        }
    })


    stream.on('event-U', (event, data) => {
            console.log("Broadcasting event-U.")
            response.write('event: ' + event + '\n' + 'data:' + JSON.stringify(data) + '\n\n')
        }

    })

    response.on('close', () => {
        console.log('client dropped me');
        response.end();
    })
}
Gooding answered 15/1, 2020 at 12:24 Comment(0)
P
0

When the client closes the socket, you must close the server side response object that was servicing it.

At least when using the http package directly, the code is something like this:

request.connection.on("close", function(){
  response.end();
  //Any other clean up, e.g. clearInterval() for any timers.
  console.log("Client closed connection. Aborting.");
  });

That was copied from p.25 of my book, Data Push Apps with HTML5 SSE.

At https://mcmap.net/q/554490/-how-to-use-server-sent-events-in-express-js there is an example for Express.js, which they write it as:

response.on('close', () => {
  console.log('client dropped me');
  //Any other clean up
  response.end();
  });

Assuming request.connection and response are the same object, then this is the same code, and therefore not specific to Express at all.

UPDATE based on code in question

Your stream.on() calls are adding a listener to an event. They are therefore part of the "clean up" in you have to do when the client disconnects. I.e.

response.on('close', () => {
  console.log('client dropped me');
  response.end();
  stream.off('event-L', eventLHandler);
  stream.off('event-U', eventUHandler);
  })

See https://nodejs.org/api/events.html#events_emitter_off_eventname_listener

Notice how you need to specify the event handler function, so cannot use anonymous functions. Refactor your code to have two event handlers (that take response as an arg).

Pansy answered 16/1, 2020 at 8:49 Comment(2)
I have added some demo code in the question for better understanding. I understand what you said in the above comment. I tried what you suggested. But even if i end the connection i can see the number of listeners keep on increasing whenever a reload happens or every time the client side automatically reconnects. This leads to warning "possible memory leaks" Also since this is event based, I get error stating "cannot write data after end".Gooding
Thank you for the suggestion. I will try that and let you know how it goes.Gooding

© 2022 - 2024 — McMap. All rights reserved.