19

我有一个 NodeJS 应用程序,它设置了一个 UNIX 套接字来公开一些进程间通信通道(某种监视的东西)。UNIX-socket 文件放置在os.tmpdir()文件夹(即/tmp/app-monitor.sock)中。

var net = require('net');
var server = net.createServer(...);
server.listen('/tmp/app-monitor.sock', ...);

我使用信号处理(SIGINT、SITERM 等)来优雅地关闭我的服务器并删除一个套接字文件。

function shutdown() {
    server.close(); // socket file is automatically removed here
    process.exit();
}

process.on('SIGINT', shutdown);
// and so on

我的应用程序正在运行forever start ...以监控它的生命周期。

我的命令有问题forever restartall。当永远这样做restartall时,它使用 aSIGKILL来终止所有子进程。SIGKILL无法由进程处理,因此我的应用程序在没有任何关闭程序的情况下死亡。

问题是使用时未删除的套接字文件SIGKILL。子进程重启后,新服务器无法启动,因为listen调用会EADDRINUSE报错。

我无法在应用程序启动过程中删除现有的套接字文件,因为'我不知道它是真正工作的套接字还是以前不干净关闭的一些痕迹。

所以,问题是......处理这种情况的更好方法是什么(SIGKILL 和 UNIX-socket 服务器)?

4

5 回答 5

47

正如其他人所提到的,您无法对 SIGKILL 做出任何回应,这通常是为什么forever(以及其他所有人)不应该使用 SIGKILL,除非在极端情况下。所以你能做的最好的就是在另一个过程中清理。

我建议你在开始时清理。当你得到 时EADDRINUSE,尝试连接到套接字。如果套接字连接成功,则另一个服务器正在运行,因此该实例应该退出。如果连接失败,则可以安全地取消链接套接字文件并创建一个新文件。

var fs = require('fs');
var net = require('net');
var server = net.createServer(function(c) { //'connection' listener
    console.log('server connected');
    c.on('end', function() {
        console.log('server disconnected');
    });
    c.write('hello\r\n');
    c.pipe(c);
});

server.on('error', function (e) {
    if (e.code == 'EADDRINUSE') {
        var clientSocket = new net.Socket();
        clientSocket.on('error', function(e) { // handle error trying to talk to server
            if (e.code == 'ECONNREFUSED') {  // No other server listening
                fs.unlinkSync('/tmp/app-monitor.sock');
                server.listen('/tmp/app-monitor.sock', function() { //'listening' listener
                    console.log('server recovered');
                });
            }
        });
        clientSocket.connect({path: '/tmp/app-monitor.sock'}, function() { 
            console.log('Server running, giving up...');
            process.exit();
        });
    }
});

server.listen('/tmp/app-monitor.sock', function() { //'listening' listener
    console.log('server bound');
});
于 2013-05-11T23:26:42.717 回答
2

你应该能够使用 SIGTERM 做你想做的事: process.on('SIGTERM', shutdown)

于 2013-05-07T21:26:15.620 回答
1
server.on('error', function (e) {
  if (e.code == 'EADDRINUSE') {
    console.log('Address in use, retrying...');
    setTimeout(function () {
      server.close();
      server.listen(PORT, HOST);
    }, 1000);
  }
});

http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback

UPD

你不能处理 SIGKILL,那么你必须清理套接字手册

这个例子永远可以正常工作

var fs = require('fs');
var net = require('net');
var server = net.createServer(function(c) {});
server.listen('./app-monitor.sock', function() {
  console.log('server bound');
});

server.on('error', function (e) {
  if (e.code == 'EADDRINUSE') {
    console.log('Address in use, retrying...');
    setTimeout(function () {
      fs.unlink('./app-monitor.sock');
    }, 1000);
  }
});
于 2013-05-07T23:32:01.303 回答
1

由于您无法处理SIGKILL并且您想永远使用(使用SIGKILL),您将不得不使用解决方法。

例如,首先发送一个信号来关闭你的服务器,然后永远重启:

kill -s SIGUSR1 $pid
# $pid contains the pid of your node process, or use
# killall -SIGUSR1 node

sleep 2
forever restart test.js

在您的 js 中处理 SIGUSR1:

process.on('SIGUSR1', gracefullyShutdownMyServer);
于 2013-05-08T19:56:39.947 回答
0

你必须选择

  1. 将 SIGKILL 更改为永远监视器中的另一个信号以在应用程序中处理
  2. 在这种情况下,使用 fs.unlink 处理您的应用程序
  3. 永远停止使用
于 2013-05-09T13:56:33.830 回答