我在编写脚本来启动本地 JBoss 实例时遇到了一个奇怪的问题。

我的代码看起来像这样:

with open("/var/run/jboss/jboss.pid", "wb") as f:
    process = subprocess.Popen(["/opt/jboss/bin/standalone.sh", "-b=0.0.0.0"])
    f.write(str(process.pid))

    try:
        process.wait()
    except KeyboardInterrupt:
        process.kill()

应该很容易理解,在运行时将 PID 写入文件,一旦我得到 KeyboardInterrupt ,就杀死子进程。

问题是在我发送 kill 信号后 JBoss 继续在后台运行,因为该信号似乎没有传播到由 standalone.sh 启动的 Java 进程。

我喜欢使用 Python 编写系统管理脚本的想法,但是有很多像这样的奇怪边缘情况,如果我用 Bash 编写它,一切都会正常工作™。

当我得到 KeyboardInterrupt 时,如何杀死整个子进程树?

最佳答案

您可以使用 psutil 库执行此操作:

import psutil

#..

proc = psutil.Process(process.pid)
for child in proc.children(recursive=True):
    child.kill()

proc.kill()

据我所知,subprocess 模块不提供任何 API 函数来检索子进程产生的子进程,os 模块也不提供。

杀死进程的更好方法可能是以下内容:
proc = psutil.Process(process.pid)
procs = proc.children(recursive=True)
procs.append(proc)

for proc in procs:
    proc.terminate()

gone, alive = psutil.wait_procs(procs, timeout=1)
for p in alive:
    p.kill()

这将使进程有机会正确终止,当超时结束时,剩余的进程将被杀死。

请注意, psutil 还提供了一个 Popen 类,该类具有与 subprocess.Popen 相同的接口(interface)以及 psutil.Process 的所有额外功能。您可能只想使用它而不是 subprocess.Popen 。它也更安全,因为 psutil 会检查进程终止时 PID 不会被重用,而 subprocess 则不会。

关于python - 在 KeyboardInterrupt 上杀死一系列子进程,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24894986/

10-08 23:07