我们有一个包装器脚本,可在后台启动DelayedJob worker。该脚本等待,直到DelayedJob工作程序完成后再退出。包装脚本是Docker容器的主要入口点,它设置了DJ工作者运行所需的一些环境。
我们注意到,尽管发出Docker停止命令时,Docker容器应等待DJ工作者正常退出(或直到最大超时),但这种情况不会发生。容器立即退出。
向容器发出Docker stop调用会将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
如您所见,在捕获信号时调用的wait
函数中的代码之前,将执行对exit_script
的p1脚本调用之后的行。
一种解决方案是将wait
替换为检查子PID是否存在的超时循环,但是为什么wait
不能按预期工作? wait
的用法不正确吗?
答案 0 :(得分:2)
等待被传入的信号中断,并且没有重新开始。您应该能够仅添加另一个等待调用以强制其完成等待。不过,可能有更好的方法。
echo "P1: waiting for p2 ($child)"
wait $child
wait $child
echo "P1: Finished waiting for p2, exiting p1"