1

Java Web App での現在のプッシュ機能の置き換えの可能性について、Node.js を評価しています。クライアントと Java バックエンドの間の仲介役のように機能する単純なロング ポーリング サーバーを作成しました。クライアントがサブスクライブを要求すると、Java サーバーは Node.js を呼び出して、サブスクライブしたクライアントに通知できます。これまでのところ問題なく動作しているようですが、メモリ リークを示す次のメッセージが表示されました。

    (node) warning: possible EventEmitter memory leak detected. 11 listeners added.
Use emitter.setMaxListeners() to increase limit.
Trace
    at EventEmitter.addListener (events.js:168:15)
    at EventEmitter.once (events.js:189:8)
    at route (C:\Users\Juan Pablo\pushserver.js:42:12)
    at Server.onRequest (C:\Users\Juan Pablo\pushserver.js:32:3)
    at Server.EventEmitter.emit (events.js:91:17)
    at HTTPParser.parser.onIncoming (http.js:1793:12)
    at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:111:23
)
    at Socket.socket.ondata (http.js:1690:22)
    at TCP.onread (net.js:402:27)

通知イベントが発行されるたびに既存のリスナーをログに記録するコード行があります。しばらく実行してみましたが、サブスクライブしたクライアントごとにリスナーが 1 つしかないことが示されています (そうあるべきです) が、警告メッセージが表示されたとき、この行はコードにありませんでした。コードは、タフな行を除いてまったく同じでした。

これはプッシュ サーバーのコードです (私はまだ Node.js を学んでいるので、少し初歩的です)。

var http = require('http');
var url = require("url");
var qs = require("querystring");
var events = require('events');
var util = require('util');

var emitter = new events.EventEmitter;

function onRequest(request, response)
{
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");
    request.setEncoding("utf8");

    if (request.method == 'POST')
    {
        var postData = "";
        request.addListener("data", function(postDataChunk)
        {
            postData += postDataChunk;
            console.log("Received POST data chunk '"+ postDataChunk + "'.");
        });

        request.addListener("end", function()
        {
            route(pathname, response, postData);
        });
    }
    else if (request.method=='GET')
    {
        var urlParts = url.parse(request.url, true);
        route(pathname, response, urlParts.query);
    }
}

function route(pathname, response, data)
{
    switch (pathname)
    {
        case "/subscription":

            emitter.once("event:notify", function(ids)
            {
                response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
                response.write(JSON.stringify(ids));
                response.end();
            });

            break;

        case "/notification":

            //show how many listeners exist
            console.log(util.inspect(emitter.listeners('event:notify'));

            emitter.emit("event:notify", data.ids);

            response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
            response.write(JSON.stringify(true));
            response.end();
            break;

        default:

            console.log("No request handler found for " + pathname);
            response.writeHead(404, {"Content-Type": "text/plain", "Access-Control-Allow-Origin": "*"});
            response.write("404 - Not found");
            response.end();
            break;
    }
}

http.createServer(onRequest).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

私は、emitter.once を使用するとイベント リスナーが一度使用されると自動的に削除されるという印象を受けていたので、クライアントが 1 つしか接続されていない場合に 11 個のリスナーを追加する方法がわかりません。通知を待っている間にクライアントが切断された場合、関連する接続リソースは破棄されないのではないかと考えています。

切断を手動で処理する必要があるかどうか、実際にどこかにリークがあるかどうか疑問に思っています。どんなアドバイスでも大歓迎です。ありがとう。

4

1 に答える 1

2

誰かが興味を持っているなら、上記のコードはリークします。リークは、通知が送信される前にクライアントが切断されたときに発生します。これを修正するには、次のようにクライアントが突然切断されたときにイベント リスナーを削除する必要があります。

case "/subscription":

        var notify = function(ids)
        {
            response.writeHead(200, {"Content-Type": "text/html", "Access-Control-Allow-Origin": "*"});
            response.write(JSON.stringify(ids));
            response.end();
        }

        emitter.once("event:notify", notify);

        //event will be removed when connection is closed
        request.on("close", function()
        {
            emitter.removeListener("event:notify", notify);
        });
        break;
于 2012-08-28T22:30:22.570 に答える