我正在尝试构建一个平台来自动部署我在NodeJS中构建的应用程序。 可以从处理这些操作的控制面板启动和停止每个应用程序。 启动应用程序时,控制面板会执行以下操作:
此设置很有效,除非尝试关闭不再需要的服务器。 即使服务器发出'关闭'事件,它仍然接受连接,最终超时,因为不再有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 );
});
正如您所看到的,我尝试将所有_handle属性置空并分离,但服务器句柄不会停止侦听端口。 当我使控制面板有一个未捕获的异常时,它会崩溃,端口绑定器也会这样做。但是应用程序节点进程没有退出并且端口保持绑定,所以我想说我没有正确地释放那些东西,但是我找不到它。
整个设置确实有效,当我提出要求时,它根本就没有关闭服务器。
编辑:我应该注意到我使用的是node.js v0.5.10
答案 0 :(得分:8)
事实证明,这是对node.js文档的错误解释导致了这个问题。 我使用的浏览器发送了一个keep-alive头,保持连接打开一段时间,以便通过相同的连接推送新的请求。
当我做了server.close()时,我希望关闭这些连接,因为文档说:
停止服务器接受新连接。
事实证明,保持活动连接没有关闭,所以只要连接打开,浏览器仍然能够发出请求,让我知道服务器仍在接受连接。
解决方法是在关闭后将requestListener重新连接到服务器。然后,当您收到连接时,关闭套接字流而不发送任何内容。现在不会处理任何新请求,一旦连接超时,它将关闭,服务器将最终完全关闭。从而为其他用途释放了端口。
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;