Node.js 领域集群工作进程断开连接

3

在查看nodejs领域文档页面上给出的示例时:http://nodejs.org/api/domain.html,使用集群重启工作进程的推荐方式是在worker部分首先调用disconnect方法,并在master部分监听disconnect事件。然而,如果您只是复制/粘贴给出的示例,您会注意到disconnect()调用并没有关闭当前的worker:

这里发生的情况是:

try {
    var killtimer = setTimeout(function() {
        process.exit(1);
    }, 30000);
    killtimer.unref();
    server.close();
    cluster.worker.disconnect();
    res.statusCode = 500;
    res.setHeader('content-type', 'text/plain');
    res.end('Oops, there was a problem!\n');
} catch (er2) {
    console.error('Error sending 500!', er2.stack);
}
  1. 我在 /error 发送一个 get 请求

    • 启动一个计时器:如果在 30 秒内没有完成,进程将被强制关闭
    • 关闭 http 服务器
    • 断开工作进程的连接(但仍然存活)
    • 显示 500 错误页面
  2. 我在 30 秒内再次发送了一个 get 请求到 error

    • 启动一个新的计时器
    • 服务器已经关闭 => 抛出错误
    • 在 "catch" 块中捕获错误,并且不向客户端返回任何结果,因此在客户端上,页面一直等待而没有任何消息。

我认为最好的方法是直接杀死工作进程,并在主进程部分监听 'exit' 事件来重新 fork。这样,在发生错误时,总是会发送 500 错误:

try {
    var killtimer = setTimeout(function() {
        process.exit(1);
    }, 30000);
    killtimer.unref();
    server.close();
    res.statusCode = 500;
    res.setHeader('content-type', 'text/plain');
    res.end('Oops, there was a problem!\n');
    cluster.worker.kill();
} catch (er2) {
    console.error('Error sending 500!', er2);
}

我不确定使用kill而不是disconnect的负面影响,但似乎disconnect正在等待服务器关闭,然而它似乎没有起作用(至少不像应该的那样)。我只想听听这方面的反馈。可能有一个我错过的很好的原因,这个例子是这样写的。谢谢。
编辑:
我刚刚用curl检查了一下,它工作得很好。 然而,我之前是用Chrome进行测试的,似乎在发送500响应后,Chrome会在服务器实际结束关闭之前发出第二个请求。 在这种情况下,服务器正在关闭而没有关闭(这意味着工作程序也在断开连接而没有被断开连接),导致第二个请求由之前的同一工作程序处理,从而: 1. 阻止服务器完成关闭 2. 第二个server.close();行被评估,它触发一个异常,因为服务器没有关闭。 3. 所有后续请求都将触发相同的异常,直到killtimer回调被调用。

我遇到了同样的问题,即断开连接的工作进程仍然接收请求并且不会关闭。我注意到,在killTimer过期后,工作进程会关闭,而这不应该发生,因为我们已经使用unref取消引用计时器,并且只是完成正常的进程,这应该终止工作进程。就像Node.js文档所述://但不要仅仅为此保持进程处于打开状态!killtimer.unref(); - Manuras
可能是由于节点版本的原因,我无法在链接上使用完全相同的代码重现这个问题: 我的节点版本是0.10.22(我刚刚更新了) Runnable的节点版本是0.10.12 - Ervadac
2个回答

3
我想通了,实际上当服务器正在关闭并且同时收到一个请求时,它会停止关闭进程。因此,它仍然接受连接,但不能再关闭了。
即使没有集群,这个简单的例子也说明了这一点:
var PORT = 8080;
var domain = require('domain');
var server = require('http').createServer(function(req, res) {
    var d = domain.create();
    d.on('error', function(er) {
            try {
                var killtimer = setTimeout(function() {
                    process.exit(1);
                }, 30000);
                killtimer.unref();
                console.log('Trying to close the server');
                server.close(function() {
                    console.log('server is closed!');
                });
                console.log('The server should not now accepts new requests, it should be in "closing state"');
                res.statusCode = 500;
                res.setHeader('content-type', 'text/plain');
                res.end('Oops, there was a problem!\n');
            } catch (er2) {
                console.error('Error sending 500!', er2);
            }
        });

        d.add(req);
        d.add(res);

        d.run(function() {
            console.log('New request at: %s', req.url);
            // error
            setTimeout(function() {
                flerb.bark();
            });
        });
});
server.listen(PORT);

只需要运行:

curl http://127.0.0.1:8080/ http://127.0.0.1:8080/ 

输出:

New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
New request at: /
Trying to close the server
Error sending 500! [Error: Not running]

现在只有一个请求:

curl http://127.0.0.1:8080/

输出:

New request at: /
Trying to close the server
The server should not now accepts new requests, it should be in "closing state"
server is closed!

例如,当Chrome请求网站图标时,会额外发出一次请求,导致服务器无法关闭。

目前我会继续使用worker.kill(),这样可以使工作进程不必等待服务器停止。


0

我大约6个月前遇到了同样的问题,可惜没有任何代码可以演示,因为那是我以前的工作。我通过显式地向工作者发送消息并同时调用断开连接来解决它。断开连接可以防止工作者接受新的工作,在我的情况下,因为我正在跟踪工作者正在进行的所有工作(这是一个具有长时间运行上传的上传服务),所以我能够等待直到它们全部完成,然后以0退出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接