2011-11-05 9 views
6

私はNodeJSで構築したアプリケーションを自動展開するためのプラットフォームを構築しようとしています。 各アプリケーションは、これらの操作を処理するコントロールパネルから開始および停止できます。 アプリケーションが起動されると、コントロールパネルは次のことを行います。Howtoは子プロセスから適切にハンドルを処理します

  • rootとして実行されているポートバインダーからのハンドルを要求します。このポートバインダーは、コントロールパネルの分岐した子です。
  • これで、コントロールパネルはこのポートで要求をリッスンします。要求が受け取られると、それは新しい要求の 'メッセージ'イベントでリッスンしているアプリケーションにクライアントソケットのハンドルを送ります。
  • アプリケーションに信号が送信されると、コントロールパネルは要求とソケットに対するすべての制御を解放します。
  • アプリケーションは、要求とソケットを解放して閉じる必要があるものを処理します。

この設定は、不要になったサーバーを停止しようとする場合を除いて、正常に機能します。 サーバーは 'close'イベントを発行しますが、引き続き接続を受け付けます。これは、もはやバインドされたrequestListenerがないために最終的にタイムアウトします。

私は、適切にリリースされていないハンドルがあると仮定しているため、サーバを起きている状態にしています。

ポートバインダー:

var options = { 
    http: require('http'), 
    https: require('https') 
}; 
process.on('message',function(data, handle) { 

    var port = data.port, 
      type = data.type, 
      server; 

    server = options[type].createServer(); 
    server.once('error', function(err) { 
     process.send({success: false, port: port, error: err}); 
    }); 
    server.listen(port,function(){ 
     var handle = server._handle; 

     process.send({success: true, port: port}, handle); 

     server.close(); 
     handle.close(); 
     server._handle = null; 
     handle = null; 
     server.removeAllListeners(); 
    }); 
}); 

コントロールパネル:

var cp = require('child_process'), 
    app, 
    types = { 
     http: require('http'), 
     https: require('https') 
    }, 
    binder = cp.fork('./portbinder'); 

binder.on('message', function(data, handle) { 
    var server = types['http'].createServer(handler); 

    server.once('close', function() { 
     server._handle = null; 
     handle = null; 
    }); 
    server.listen(handle); 
}); 

function handler(req, resp) { 
    app = app || cp.fork('./application'), 
    socket = resp.socket, 

    _handle = socket._handle, 
    _req = {}, 
    _resp = {}, 
    _socket = {}; 

    // Copy transferable fields. 
    for(i in req) { 
     if(typeof req[i] != 'function' && i != 'socket' && i != 'connection' && i != 'client') { 
      _req[i] = req[i]; 
     } 
    } 

    for(i in resp) { 
     if(typeof resp[i] != 'function' && i != 'socket' && i != 'connection' && i != 'client') { 
      _resp[i] = resp[i]; 
     } 
    } 

    for(i in socket) { 
     if(typeof socket[i] != 'function' && 
      i != '_handle' && i != '_httpMessage' && 
      i != '_idlePrev' && i != '_idleNext' && i != 'server') { 
       _socket[i] = socket[i]; 
     } 
    } 

    // Send request to application. 
    app.send({ 
     type: 'request', 
     data: { 
      req: _req, 
      resp: _resp, 
      socket: _socket 
     } 
    }, _handle); 

    // Release the handle here without sending anything to the browser. 
    socket._write = function() {}; 
    resp.end(); 
    socket.destroy(); 
    socket._handle = null; 
    _handle = null; 
}; 

用途:

私はヌルとすべて_handleプロパティを切り離ししようとして見ることができるようにI持っているが、サーバーハンドルはポートでのリッスンを停止しません。 コントロールパネルにキャッチされない例外が発生すると、クラッシュし、ポートバインダーも同様に機能します。しかし、アプリケーションノードプロセスは終了せず、ポートはバインドされたままになっているので、私はそこに何かを適切にリリースしていませんが、見つけられません。

セットアップ全体が機能しますが、私が尋ねるとサーバーを閉じることはありません。

EDIT:それはそれは、この問題につながったのNode.jsドキュメントの誤解です結局のところ、私はおそらく私がNode.jsのv0.5.10に

+0

あなたはv0.6.0で試したことがありますか?私は、彼らが子供のためのより多くの機能が、今日 –

+0

インストールv0.6.0を処理し、それでも問題が解決しない追加されていると信じています。ドキュメントには何も新しいことは書かれていません。今日のソースを見ていきます。ドキュメント化されていないかもしれません。 –

答えて

8

を使用していますことに注意してください。 私が使用していたブラウザは、同じ接続上で新しい要求をプッシュするために接続を開いたままにしておくキープアライブヘッダーを送信しました。

私はserver.closeをしました()のドキュメントが言うので、私はこれらの接続がクローズされると予想さ:

は新しい接続を受け付けからサーバーを停止します。

キープアライブ接続が閉じられていないため、接続が開いている限りブラウザは依然としてリクエストを実行できたため、サーバーが接続を受け入れているという考えが得られました。

これを解決するには、requestListenerを閉じた後でサーバーにrequestListenerを再度接続します。接続を受け取ったら、何も送信せずにソケットストリームを閉じます。今度は新しいリクエストは処理されず、接続がタイムアウトするとすぐにサーバーは終了し、サーバーは最終的に完全にシャットダウンします。したがって、他の用途のためにポートを解放します。

この修正を適用すると、コードをクリーンアップしてハンドルを解放するコードを削除することもできます。 node.jsガベージコレクタはハンドルオブジェクトを正しく取得し、接続が切断されるとハンドルも破棄されるようになりました。

// All of this is no longer needed. 
socket._write = function() {}; 
socket.end(); 
socket.destroy(); 
socket._handle = null; 
handle = null; 
関連する問題