捕获信号时如何正确等待bash子进程完成
Posted
技术标签:
【中文标题】捕获信号时如何正确等待bash子进程完成【英文标题】:How to properly wait for bash child process to complete when trapping signals 【发布时间】:2019-04-10 17:39:04 【问题描述】:我们有一个包装脚本,它在后台启动 DelayedJob 工作者。此脚本等到 DelayedJob 工作程序完成后才退出。包装脚本是 Docker 容器的主要入口点,并设置了 DJ 工作者运行所需的一些环境。
我们注意到,当发出 Docker stop 时,Docker 容器应该等到 DJ 工作者正常退出(或直到最大超时),但这并没有发生。容器立即退出。
向容器发出 Docker 停止调用会向主进程(包装脚本)发送 SIGTERM。在包装脚本中,我们捕获 SIGTERM 并将信号传递给 DJ 工作进程。
这仍然不起作用。我使用简单的 Bash 脚本创建了一个测试用例来说明问题。
脚本 p1:
#!/bin/bash
echo "P1: starting p1 and running p2 in bg"
exit_script()
echo "P1: Caught sigterm in p1, sending TERM to p2"
kill -TERM $child
trap exit_script SIGINT SIGTERM
./p2 &
child=$!
echo "P1: waiting for p2 ($child)"
wait $child
echo "P1: Finished waiting for p2, exiting p1"
脚本 p2:
#!/bin/bash
echo "P2: starting p2"
exit_script()
echo "P2: Caught sigterm"
NEXT_WAIT_TIME=0
until [ $NEXT_WAIT_TIME -eq 10 ]; do
echo "P2: EXIT_SCRIPT loop $NEXT_WAIT_TIME"
sleep $(( NEXT_WAIT_TIME++ ))
done
exit
trap exit_script SIGINT SIGTERM
echo "P2: Sleeping for a while"
NEXT_WAIT_TIME=0
until [ $NEXT_WAIT_TIME -eq 10 ]; do
echo "P2: Main Loop $NEXT_WAIT_TIME"
sleep $(( NEXT_WAIT_TIME++ ))
done
echo "P2: Finished sleeping in p2"
输出:
MBP:$ ./p1
P1: starting p1 and running p2 in bg
P1: waiting for p2 (74039)
P2: starting p2
P2: Sleeping for a while
P2: Main Loop 0
P2: Main Loop 1
P2: Main Loop 2
P2: Main Loop 3
P2: Main Loop 4
P1: Caught sigterm in p1, sending TERM to p2
P1: Finished waiting for p2, exiting p1
MBP:$ P2: Caught sigterm
P2: EXIT_SCRIPT loop 0
P2: EXIT_SCRIPT loop 1
P2: EXIT_SCRIPT loop 2
P2: EXIT_SCRIPT loop 3
P2: EXIT_SCRIPT loop 4
P2: EXIT_SCRIPT loop 5
P2: EXIT_SCRIPT loop 6
P2: EXIT_SCRIPT loop 7
P2: EXIT_SCRIPT loop 8
P2: EXIT_SCRIPT loop 9
如您所见,p1 脚本调用wait
之后的行在捕获信号时调用的exit_script
函数中的代码之前执行。
解决方案是将wait
替换为检查子PID 是否存在的超时循环,但为什么wait
不能按预期工作? wait
的用法有误吗?
【问题讨论】:
【参考方案1】:等待被传入信号中断,不会重新启动。您应该能够添加另一个等待调用来强制它完成等待。不过可能有更好的方法来做到这一点。
echo "P1: waiting for p2 ($child)"
wait $child
wait $child
echo "P1: Finished waiting for p2, exiting p1"
【讨论】:
以上是关于捕获信号时如何正确等待bash子进程完成的主要内容,如果未能解决你的问题,请参考以下文章