终止 bash 脚本不会终止子进程
Killing a bash script does not kill child processes
我写了一个测试脚本,它运行另一个脚本来启动服务器进行测试。当测试完成时,一条 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')
在您的服务器中有一个处理信号的处理程序
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")
要杀死一个 child 进程及其所有 children 你可以使用 process.kill
和一个否定 pid
(杀死一个进程组)
var child = child_process.spawn('scripts/start-node.sh', {detached: true})
// Later…
process.kill(-child.pid, 'SIGKILL');
请参阅 options.detached
的 child_process
文档的详细信息
On non-Windows, if the detached option is set, the child process will be made the leader of a new process group and session.
这里引用了 man 2 kill
的一部分以了解一些细节:
If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.
另一个选项可能是在您的 shell 脚本中使用 trap
来拦截信号并杀死所有 children 并使用 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
node is creating child process every-time we kill it. So it's not
possible to kill the process from kill,pkill or killall commands. So
we are removing node command to make forking process fail and then we
kill the process.Finally we restore the node command.
我写了一个测试脚本,它运行另一个脚本来启动服务器进行测试。当测试完成时,一条 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')
在您的服务器中有一个处理信号的处理程序
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")
要杀死一个 child 进程及其所有 children 你可以使用 process.kill
和一个否定 pid
(杀死一个进程组)
var child = child_process.spawn('scripts/start-node.sh', {detached: true})
// Later…
process.kill(-child.pid, 'SIGKILL');
请参阅 options.detached
child_process
文档的详细信息
On non-Windows, if the detached option is set, the child process will be made the leader of a new process group and session.
这里引用了 man 2 kill
的一部分以了解一些细节:
If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.
另一个选项可能是在您的 shell 脚本中使用 trap
来拦截信号并杀死所有 children 并使用 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
node is creating child process every-time we kill it. So it's not possible to kill the process from kill,pkill or killall commands. So we are removing node command to make forking process fail and then we kill the process.Finally we restore the node command.