2012-08-24 4 views
1

Java Web App에서 현재 푸시 기능을 대체 할 수있는 Node.js를 평가 중입니다. 클라이언트와 Java 백엔드 사이의 중개자처럼 작동하는 간단한 긴 폴링 서버를 작성했습니다. 클라이언트가 구독 요청을하면 Java 서버는 Node.js를 호출하여 구독 클라이언트에 알릴 수 있습니다. 그것은 지금까지 잘 동작하는 것,하지만 난 메모리 누수를 가리키는 다음과 같은 메시지가 있어요 :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) 

나는 통지 이벤트가 방출 될 때마다 기존의 청취자를 기록 코드의 라인을 가지고 있습니다. 나는 그것을 잠시 동안 실행 시켰고 구독 클라이언트 당 오직 하나의 청취자가 있다는 것을 보여 주지만, 경고 메시지를 받았을 때이 라인은 코드에 없었습니다. 이 코드는 그 라인을 제외하고는 똑같습니다.

푸시 서버의 코드입니다 (나는 아직도 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가 자동으로 한 번 이벤트 리스너를 제거 것이라는 인상이었다 그것은 사용 되었기 때문에 하나의 클라이언트 만 연결된 경우 11 명의 청취자가 추가 될 수 있었는지는 알 수 없습니다. 아마도 클라이언트가 알림을 기다리는 동안 연결을 끊으면 연결된 연결 리소스가 삭제되지 않을 수도 있습니다.

내가 단선을 수동으로 처리해야하는지, 어딘가에 실제로 누출이 있는지 궁금합니다. 어떤 조언을 환영합니다. 감사.

답변

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;