Nodejs - процесс зависает при выходе (Ctrl + C)

У меня есть проект node.js, который делает много вещей, он порождает дочерние процессы, он открывает сервер http и socket.io и т.д.

Когда я запускаю его с консоли, закрывая его Ctrl+C, он просто зависает. Из webstorm остановка процесса - это двухэтапный процесс, сначала я нажимаю стоп, затем мне нужно снова нажать кнопку, только во второй раз, когда кнопка представляет собой значок черепа.

Теперь я понимаю, что он оставляет что-то открытое или висячее, но я просто не могу понять, что, я пытался отслеживать все места, где я запускаю процесс, и убедиться, что я их правильно убиваю.

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

EDIT: я загрузил pstree, чтобы узнать, остается ли какой-либо из дочерних процессов, оставшихся в процессе основного процесса. Похоже, все они заканчиваются правильно - основной node процесс остается единственным.

Ответы

Ответ 1

Скрипты сами несут ответственность за надлежащее завершение работы после прослушивания события SIGINT, поскольку обработчик по умолчанию (убивающий процесс) отключен.

Посмотрите эту примерную программу:

process.on('SIGINT', function() {
    console.log('SIGINT');
});
console.log('PID: ', process.pid);

var http = require('http'); // HTTP server to keep the script up long enough
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

Выполните его, а затем попробуйте убить его: Он не будет работать. Сигнал SIGINT всегда будет передан вашему обработчику сигнала настраиваемого построения. Чтобы правильно закрыть процесс, вам придется вручную вызвать process.exit():

process.on('SIGINT', function() {
    console.log('SIGINT');
    process.exit();
});
console.log('PID: ', process.pid);

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

process.exit() будет:


Короче говоря: ваш код, вероятно, где-то слушает SIGINT. Вы можете получить список этих слушателей через:

var listeners = process.listeners('SIGINT');

Вы даже можете распечатать их на консоли:

for (var i = 0; i < listeners.length; i++) {
    console.log(listeners[i].toString());
}

Используя приведенную выше информацию, вы можете легко скомпилировать еще один SIGINT -handler, который будет перечислять все обработчики, а затем чисто выйти из процесса, надеясь, что ваш путь к непослушным:

process.on('SIGINT', function() {
    console.log('Nice SIGINT-handler');
    var listeners = process.listeners('SIGINT');
    for (var i = 0; i < listeners.length; i++) {
        console.log(listeners[i].toString());
    }

    process.exit();
});

Полная программа для тестирования:

process.on('SIGINT', function() {
    console.log('Naughty SIGINT-handler');
});
process.on('exit', function () {
    console.log('exit');
});
console.log('PID: ', process.pid);

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

process.on('SIGINT', function() {
    console.log('Nice SIGINT-handler');
    var listeners = process.listeners('SIGINT');
    for (var i = 0; i < listeners.length; i++) {
        console.log(listeners[i].toString());
    }

    process.exit();
});