Изящно завершение работы сервера UNIX-сокетов в NodeJS под управлением Forever

17

У меня есть приложение NodeJS, которое устанавливает UNIX-сокет, чтобы открыть какой-то канал межпроцессного обмена (какой-то материал для мониторинга). Файл UNIX-сокета помещается в папку os.tmpdir() (т. Е.% Co_de%).

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

Мое приложение работает с /tmp/app-monitor.sock , чтобы контролировать его жизненный цикл.

У меня проблема с командой forever start ... . Когда навсегда выполняется forever restartall , используется restartall для завершения всех дочерних процессов. SIGKILL не может обрабатываться процессом, поэтому мое приложение умирает без каких-либо остановок.

Проблема заключается в файле сокета, который не удаляется при использовании SIGKILL . После перезапуска дочернего процесса новый сервер не может быть запущен, потому что вызов SIGKILL вызовет ошибку listen .

Я не могу удалить существующий файл сокета во время запуска приложения. «Я не знаю, действительно ли это настоящий рабочий сокет или некоторые следы предыдущего нечистого отключения.

Итак, вопрос в том, что ... Каков лучший способ справиться с такой ситуацией (сервер SIGKILL и UNIX-сокетов)?

    
задан Olegas 23.04.2013 в 22:08
источник

5 ответов

37

Как уже отмечали другие люди, вы ничего не можете сделать в ответ на 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');
});
    
ответ дан Old Pro 12.05.2013 в 01:26
источник
2

вы можете использовать SIGTERM для выполнения того, что вы хотите: % Co_de%     

ответ дан Clintm 07.05.2013 в 23:26
источник
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);
  }
});

Ссылка

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);
  }
});
    
ответ дан amirka 08.05.2013 в 01:32
источник
1

Поскольку вы не можете обработать SIGKILL и хотите использовать forever (который использует 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);
    
ответ дан laktak 08.05.2013 в 21:56
источник
0

вы должны выбрать

  1. измените SIGKILL на другой сигнал навсегда-мониторе, чтобы обрабатывать приложение
  2. позаботьтесь о своем приложении в этом случае, используя fs.unlink
  3. остановить использование навсегда
ответ дан amirka 09.05.2013 в 15:56
источник