如何正确处理subprocess的句柄

我正在尝试构build一个平台来自动部署我在NodeJS中构build的应用程序。 每个应用程序可以从处理这些操作的控制面板启动和停止。 启动应用程序时,控制面板执行以下操作:

  • 从以root用户身份运行的端口绑定程序请求句柄。 该端口绑定器是控制面板的分叉子。
  • 现在控制面板监听这个端口上的请求。 一旦接收到请求,就会将客户端套接字的句柄发送到正在侦听新消息的“消息”事件的应用程序。
  • 一旦应用程序发出信号,控制面板将释放对请求和套接字的所有控制。
  • 应用程序做它需要做的事情,释放并closures请求和套接字。

除非尝试closures不再需要的服务器,否则此设置运行良好。 即使服务器发出“closures”事件,它仍然接受连接,最终超时,因为没有再绑定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; }; 

应用:

 function reattach( target, properties ) { var i; for( i in properties ) { target[i] = properties[i]; } return target; }; function handler( req, resp ) { resp.end('hello world!'); }; process.on('message', function( param, handle ) { var _req = param.data.req, _resp = param.data.resp, _socket = param.data.socket, socket, resp, req; // Create a socket and reattach its properties. socket = new net.Socket({handle:handle}); reattach( socket, _socket ); // Create a request and reattach its properties. req = new http.IncomingMessage(socket); reattach( req, _req ); // Create a response and reattach its properties. resp = new http.ServerResponse( req ); resp.assignSocket(socket); reattach( resp, _resp ); // Help closing down sockets after request is handled. resp.once('finish', function() { socket._write = function() {}; socket.end(); socket.destroy(); socket._handle = null; handle = null; }); handler( req, resp ); }); 

正如你可以看到我试图null和分离所有的_handle属性,但服务器句柄不停止监听端口。 当我使控制面板有一个未捕获的exception崩溃,端口绑定也是如此。 但是,应用程序节点进程不退出,端口保持绑定,所以我正在做,我没有妥善释放那里,但我无法find它。

整个安装程序确实起作用,当我提出要求时,根本不会closures服务器。

编辑:我可能应该注意到,我使用node.js v0.5.10

事实certificate这是对导致这个问题的node.js文档的误解。 我使用的浏览器发送了一个保持连接的头文件,保持连接打开一段时间,以通过相同的连接推送新的请求。

当我做了一个server.close()我希望这些连接被closures,因为文档说:

停止服务器接受新的连接。

事实certificate,保持活动连接并没有closures,所以只要连接打开,浏览器仍然可以请求,这让我知道服务器仍然在接受连接。

解决这个问题的方法是closuresrequestListener到你的服务器。 然后当你收到一个连接,closures套接字stream而不发送任何东西。 现在不会有新的请求被处理,并且只要连接超时就会closures,服务器将最终完全closures。 从而腾出了其他用途的港口。

 server.close(); // Drop any new request immediately, while server ditches old connections. server.on('request', function( req, resp ) { req.socket.end(); }); server.once('close', function(){ // Remove the listeners after the server has shutdown for real. server.removeAllListeners(); }); 

把这个修复的地方,我也可以清理我的代码,并删除代码释放句柄。 node.js垃圾回收器现在正确地拿起句柄对象,当连接死亡时,句柄也是如此。

 // All of this is no longer needed. socket._write = function() {}; socket.end(); socket.destroy(); socket._handle = null; handle = null;