如何将SIGTERM信号传播给subprocess创建的子进程
现象原因
- Linux系统默认信号仅发送给指定的单个进程,不会自动向下传递给其子进程。执行
kill -15 <a.py PID>时,只有a.py进程收到SIGTERM信号。 - 原始a.py未注册SIGTERM信号处理逻辑,收到信号后直接终止退出,其启动的b.py子进程未收到终止信号,成为孤儿进程被系统init进程托管,因此会持续在后台运行输出日志。
解决方案
要实现多级进程链(a.py->b.py->c.py->d.py)仅最内层配置清理逻辑即可全链路透传信号的要求,可采用进程组信号批量转发方案,实现逻辑如下:
- 所有非最内层的父进程(a.py、b.py、c.py)统一添加通用信号转发逻辑,无需处理业务清理:
- 注册SIGINT、SIGTERM等终止信号的处理函数
- 启动子进程时通过
preexec_fn=os.setsid参数让子进程创建独立进程组,其所有后代进程默认都会归属到该进程组 - 父进程收到终止信号时,调用
os.killpg()将信号转发给子进程对应的整个进程组,所有后代进程都会收到相同的终止信号
- 仅最内层进程(如示例中的b.py,多级场景下的d.py)保留业务相关的信号清理逻辑即可,无需额外修改。
修改后的a.py示例代码:
#!/usr/bin/env python3 # a.py import signal import subprocess import os import sys child_proc = None def forward_signal(signum, frame): if child_proc: # 向子进程所在的整个进程组转发信号,覆盖所有后代进程 os.killpg(os.getpgid(child_proc.pid), signum) sys.exit(128 + signum) def main(): global child_proc print(f'Starting process {os.getpid()}') # 注册需要转发的终止信号 signal.signal(signal.SIGINT, forward_signal) signal.signal(signal.SIGTERM, forward_signal) # 启动子进程时让其创建新的进程组 child_proc = subprocess.Popen('./b.py', preexec_fn=os.setsid) child_proc.wait() sys.exit(child_proc.returncode) if __name__ == '__main__': main()
如果b.py需要继续启动c.py,仅需给b.py添加上述相同的通用转发逻辑即可,原有清理逻辑无需调整。
内容的提问来源于stack exchange,提问作者user1011113
相关产品推荐
相关产品推荐

