Изящно завершение работы 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-сокетов)?
Ответы
Ответ 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
- остановить использование навсегда