bash脚本中SIGTERM无法传递给Terraform进程的原因探究
问题
在流水线中通过脚本运行Terraform,希望确保流水线任务被中止时,Terraform能收到SIGTERM信号。最初编写的脚本如下:
_term() { tf_pid="$(pidof terraform)" kill -TERM ${tf_pid} wait ${tf_pid} } trap _term SIGTERM ... terraform "$@"
采用这种方式时SIGTERM无法传递给Terraform,但改用terraform "$@" & wait $!的调用方式后,信号能正常传递。请问这是为什么?
原因分析
这两种写法的核心区别在于脚本和Terraform进程的关联方式,以及信号处理的时机:
直接执行
terraform "$@"的问题
当脚本直接运行这条命令时,Terraform会成为脚本的前台子进程,脚本会阻塞在这里等待Terraform执行完毕。此时流水线向脚本发送SIGTERM时,存在两个关键问题:pidof terraform存在竞态:如果信号触发时机刚好在Terraform启动前、或执行结束后,会获取不到正确PID;如果系统中还有其他Terraform进程在运行,还会拿到错误的PID,导致无法精准发送信号。- 进程上下文限制:脚本处于等待前台子进程的状态时,收到SIGTERM后会执行
trap函数,但此时Terraform仍在前台运行,脚本的信号处理流程无法及时将SIGTERM传递给Terraform,甚至会因为进程组的上下文问题,导致信号根本无法送达目标进程。
用
terraform "$@" & wait $!能成功的原因
这种写法是将Terraform放到后台运行,然后脚本通过wait $!等待这个特定的Terraform进程($!是Shell内置变量,代表最后一个启动的后台进程的PID):- 精准定位PID:不需要依赖
pidof猜测进程ID,直接用$!就能明确目标Terraform进程,彻底避免了竞态问题。 - 可中断的等待状态:脚本执行
wait $!时处于可中断的等待状态,收到SIGTERM后会立即唤醒并执行trap函数,此时用正确的PID发送SIGTERM,能确保信号准确传递给Terraform进程。
- 精准定位PID:不需要依赖
总结来说,第一种写法的信号传递依赖不确定的PID获取方式,还受进程上下文限制;第二种写法通过明确跟踪目标进程PID,让信号处理的时机和目标都更精准,因此能正常传递SIGTERM。
内容的提问来源于stack exchange,提问作者Bernard Halas
相关产品推荐
相关产品推荐

