Подтвердить что ты не робот

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

У меня есть приложение NodeJS, которое устанавливает UNIX-сокет, чтобы открыть какой-то канал межпроцессного обмена (какой-то материал для мониторинга). Файл UNIX-сокета помещается в папку 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, он использует SIGKILL для завершения всех дочерних процессов. SIGKILL не может обрабатываться процессом, поэтому мое приложение умирает без каких-либо процедур выключения.

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

вы можете использовать SIGTERM для выполнения того, что вы хотите: process.on('SIGTERM', shutdown)

Ответ 3

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

Ответ 4

Поскольку вы не можете обрабатывать 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);

Ответ 5

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

  • измените SIGKILL на другой сигнал навсегда-мониторе, чтобы обрабатывать приложение
  • позаботьтесь о своем приложении в этом случае, используя fs.unlink
  • остановить использование навсегда