Node.js: Long-polling with EventEmitter and Express 4.x | Catching request close

I'm long-polling node.js route with JQuery's ajax request (xhr). This sends a GET request to my Express server and listens for message bus events. I'm setting a timeout on that GET request (as my proxy would kill long requests). So after the timeout, an abort event should be sent by the client to the server.

I want to catch that abort/close/finish event and remove the relevant message bus listener/subscriber.

But I struggle. I tried req.on("close"..) and the on-finished npm module, but that didn't work for me. I'm also not much more clever after reading the http documentation of node: https://nodejs.org/api/http.html.

Any ideas how to tackle this beast? Or better ways to remove listeners to prevent memory leaks?

Server side essentials:

// server.js
var express = require("express");
var EventEmitter = require("events").EventEmitter;
var messageBus = new EventEmitter();
messageBus.setMaxListeners(20);

var REST_PORT = (process.env.PORT || 5000);
var app = express();

app.get("/events", (req, res) => {
    var listener = function(res) {
        messageBus.once("message", function(data) {
            res.status(200).json(data);
        });
    };
    req.on("abort", function() { //I tried also "aborted", "close", "closed", "finish", "finished"..no luck
        messageBus.removeListener("message", listener);
    });

    listener(res);
    console.log("Total listeners to 'message' events:", messageBus.listeners("message").length);
});

// other messageBus.emit logic ..

app.listen(REST_PORT, () => {
    console.log("Application ready on port " + REST_PORT);
});

Client side essentials:

//client.js
$.ajax({
    method: "GET",
    async: true,
    url: "/events",
    success: function(data) {
        callback(data);
    },
    complete: function(request, status, err) {
        if (status == "timeout" || status == "success") {
            console.log("LOG: Normal long-polling timeout or successful poll, continuing.");
            longPoll();
        } else {
            console.warn("WARN: Server probably offline, retrying in 2 sec.");
            setTimeout(function() {
                longPoll();
            }, 2000);
        }
    },
    timeout: 30000
});

Thank you!

Answers:

Answer

If this helps someone, I finally decided to implement the long-polling differently and killing the client request at the server side after certain timeout. This works for me nicely and after reflection, is probably better mechanism than trusting the client to close the requests correctly.

setTimeout(() => {
    if (!responded) {
        messageBus.removeListener("message", listener);
        res.status(204).end();
    }
}, 30000);
Answer

I recommend aborting your custom long-polling system altogether and using one of the existing messaging/socket-type systems. There are many that are fully formed. socket.io is the most popular still and works well, but some alternatives like these might be better https://www.reddit.com/r/node/comments/4ktqae/socketio_alternatives/

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.