有一个面向 Linux 的 Python 程序正在启动 Puppet 子进程。Puppet 是一个配置管理软件,在执行它时会启动许多子进程(yum、curl、自定义脚本等)。Python 代码有一个看门狗,如果 puppet 子进程运行时间过长,它会杀死它。在当前版本中,它使用 os.kill 来做到这一点。问题是,当 puppet 进程在超时时被终止时,它的孤儿会被附加到“init”并继续运行。通常,这些孩子是超时的初始原因。
第一次尝试是杀死整个进程组(os.killpg)。但是 kill 调用失败并出现 OSError(3, 'No such process')。在研究了流程管理文档后,我了解到它不起作用,因为 puppet 本身在一个单独的流程组中启动了 ruby 流程。此外,进程组不会被子进程继承,因此 os.killpg 无论如何也无济于事。是的,POSIX 允许设置具有某些限制的子进程的 PGID,但它需要对新子进程进行迭代监视,并且在我的情况下看起来像是 hack。
下一次尝试是在单独的外壳(“sh -c”)/“su”环境/setsid(以各种组合)中运行 Puppet。期望的结果是在新会话中启动此进程(和子进程)。我希望它将允许模拟远程 ssh 连接断开之类的东西:向会话负责人发送 SIGHUP,例如 puppet 进程,会将 SIGHUP 发送到整个子树。所以我将能够杀死整棵树。通过远程 SSH 连接运行 puppet 的实验表明,这种方法似乎有效:所有进程在终端断开连接后都会死掉。我还没有从 Python 实现这种行为。这种方法是否正确,我是否遗漏了什么或者它是一个丑陋的黑客?
我看到的另一种方法是将 SIGSTOP 发送到树中的每个进程(在树中至少有一个正在运行的进程时进行迭代以避免竞争条件),然后单独杀死每个进程。这种方法可行,但看起来不太优雅。
问题与 Python 代码无关,它还会在从控制台运行“puppet apply”并使用“kill”命令发送信号时重现。
是的,我知道 Puppet 有一个用于所述目的的“超时”关键字,但我正在寻找一个更通用的解决方案,不仅适用于 Puppet,而且适用于任何富有成效的子流程。