简体   繁体   English

在Forever下运行的NodeJS上正常关闭UNIX套接字服务器

[英]Gracefully shutdown UNIX-socket server on NodeJS running under Forever

I have an NodeJS application which sets up a UNIX-socket to expose some interprocess communication channel (some kind of monitoring stuff). 我有一个NodeJS应用程序,它设置一个UNIX套接字来公开一些进程间通信通道(某种监视的东西)。 UNIX-socket file is placed in os.tmpdir() folder (ie /tmp/app-monitor.sock ). UNIX套接字文件放在os.tmpdir()文件夹中(即/tmp/app-monitor.sock )。

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

I use a signal handling (SIGINT, SITERM, etc...) to gracefully shutdown my server and remove a socket file. 我使用信号处理(SIGINT,SITERM等...)来正常关闭我的服务器并删除套接字文件。

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

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

My application is running with forever start ... to monitor it's lifecycle. 我的应用程序正在运行, forever start ...监控它的生命周期。

I have a problem with forever restartall command. 我有一个forever restartall命令的问题。 When forever doing restartall it's using a SIGKILL to terminate all child processes. 当永远restartall它使用SIGKILL来终止所有子进程。 SIGKILL can't be handled by a process so my app dies without any shutdown procedures. SIGKILL无法由进程处理,因此我的应用程序在没有任何关闭过程的情况下死亡。

The problem is a socket file which is not removed when SIGKILL is used. 问题是套接字文件在使用SIGKILL时不会被删除。 After the child process is restarted, new server can't be started cause' a listen call will cause a EADDRINUSE error. 重新启动子进程后,无法启动新服务器导致' listen调用将导致EADDRINUSE错误。

I can't remove a existing socket file during an app startup cause' I don't know if it a real working socket or some traces of a previous unclean shutdown. 我无法在应用启动期间删除现有的套接字文件导致'我不知道它是真正的工作套接字还是以前不干净关闭的痕迹。

So, the question is... What is the better way to handle such situation (SIGKILL and UNIX-socket server)? 所以,问题是......处理这种情况的更好方法是什么(SIGKILL和UNIX-socket服务器)?

As other people have mentioned, you cannot do anything in response to SIGKILL, which is in general why forever (and everybody else) should not be using SIGKILL except in extreme circumstances. 正如其他人提到的那样,你不能做任何事情来回应SIGKILL,这通常是为什么forever (和其他人)不应该使用SIGKILL,除非在极端情况下。 So the best you can do is clean up in another process. 所以你能做的最好就是在另一个过程中清理。

I suggest you clean up on start. 我建议你在开始时清理一下。 When you get EADDRINUSE , try to connect to the socket. 当您获得EADDRINUSE ,请尝试连接到套接字。 If the socket connection succeeds, another server is running and so this instance should exit. 如果套接字连接成功,则另一台服务器正在运行,因此该实例应该退出。 If the connection fails then it is safe to unlink the socket file and create a new one. 如果连接失败,则可以安全地取消链接套接字文件并创建一个新文件。

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');
});

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

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 http://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback

UPD UPD

you cant handle SIGKILL, then you must cleanup socket manual 你无法处理SIGKILL,那么你必须清理套接字手册

this example work fine with forever 这个例子永远工作得很好

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);
  }
});

Since you cannot handle SIGKILL and you want to use forever (which uses SIGKILL ) you will have to use a workaround. 由于您无法处理SIGKILL并且您想永久使用(使用SIGKILL ),因此您必须使用变通方法。

For example, first send a signal to shutdown your server and then do the forever restart: 例如,首先发送信号以关闭服务器,然后永远重启:

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

sleep 2
forever restart test.js

In your js handle SIGUSR1: 在你的js句柄SIGUSR1:

process.on('SIGUSR1', gracefullyShutdownMyServer);

you must choose 你必须选择

  1. change SIGKILL to another signal in forever-monitor to handle in app 将SIGKILL更改为永久监视器中的另一个信号,以便在app中处理
  2. take care of your app in this case, using fs.unlink 在这种情况下,请使用fs.unlink处理您的应用
  3. stop using forever 永远停止使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM