Убийство скрипта bash не убивает дочерние процессы

Я написал тестовый скрипт, который запускает другой скрипт, чтобы запустить сервер для тестирования. Когда испытания завершены SIGKILL сообщение отправляется процессу сервера, однако при повторном запуске тестового сценария сервер выдает EADDRINUSE ошибка (я нахожусь в среде node.js), которая означает, что порт, к которому пытается подключиться сервер, в настоящее время используется. Процесс, который мы пытались убить SIGKILL все еще работает. Я не верю, что это проблема конкретного узла, а скорее отсутствие у меня понимания, как работают процессы bash.

Вот некоторые особенности, это мой стартовый скрипт scripts/start-node.sh:

#!/bin/bash

node_modules/.bin/babel-node --stage 0 index.js

Это мой узел сервера называется index.js (Я не был автором process слушатели событий):

Http.createServer(…).listen(PORT, () => console.log(`Server listening on ${PORT}`))

И стартовый скрипт контролируется с помощью узла child_process модуль:

var child = child_process.spawn('scripts/start-node.sh')
// Later…
child.kill('SIGKILL')

3 ответа

Решение

Чтобы убить дочерний процесс и всех его детей, вы можете использовать process.kill с отрицательным pid (убить группу процессов)

var child = child_process.spawn('scripts/start-node.sh', {detached: true})
// Later…
process.kill(-child.pid, 'SIGKILL');

Смотрите подробности на child_process документация для options.detached

В не-Windows, если установлена ​​опция отсоединения, дочерний процесс будет сделан лидером новой группы процессов и сеанса.

Ссылка здесь часть man 2 kill для некоторых деталей:

Если pid меньше -1, то sig отправляется каждому процессу в группе процессов с идентификатором -pid.


Другой вариант может использовать trap в вашем сценарии оболочки, чтобы перехватить сигнал и убить всех детей и используя child.kill('SIGTERM') от node (как SIGKILL не будет перехвачен trap)

#!/bin/bash

trap 'kill $(jobs -p)' EXIT
node_modules/.bin/babel-node --stage 0 index.js

Просто:

#!/bin/bash
if pgrep -x "node" > /dev/null
then
mv -f  /usr/local/bin/node /usr/local/bin/node.1
killall  node
mv -f /usr/local/bin/node.1 /usr/local/bin/node
which node
else
echo "process node not exists"
fi

узел создает дочерний процесс каждый раз, когда мы его убиваем. Поэтому невозможно убить процесс с помощью команд kill, pkill или killall. Таким образом, мы удаляем команду узла, чтобы вызвать сбой процесса разветвления, а затем убиваем процесс. Наконец, мы восстанавливаем команду узла.

Иметь обработчик для сигналов процесса на вашем сервере

server.js

 var http = require('http');

function handleRequest(request, response){
    response.end("Hello");
}
var server = http.createServer(handleRequest);

server.listen(3000, function(){console.log("listening...")});
process.title="testserver"

process.on('SIGQUIT', function() {
  server.close()
});

startup.sh

 #!/bin/bash
 node server.js & echo "started"

а затем есть "shutdown.sh".

shutdown.sh

#!/bin/bash
pkill -QUIT testserver & echo "stoped"

Он убьет все процессы с таким именем, если вы создадите многократные процессы в вашем файле start-node.sh. Таким образом, вы можете иметь некоторый код очистки при завершении работы, например, закрытие всех соединений и т. Д.

и в своем тесте вы можете сделать

var exec = require('child_process').exec;
exec("./start.sh")
// later...
exec("./stop.sh")

У вас есть выход 0 в вашем скрипте?

Пример:

    #!/bin/bash

    ifconfig

    exit 0
Другие вопросы по тегам