在 Rails 应用程序上从 Ruby 启动一个进程并在不离开僵尸进程的情况下将其杀死

Starting a process and killing it from Ruby on Rails app without leaving zombie process

我正在 Rails 应用程序上开发 Ruby。部分功能是通过串行端口启动和关闭与 Modbus 从站的连接,获取数据并将其存储到数据库中。此外,我在 python 中制作了一个脚本,它完全满足我的需要,因此我不想重新发明轮子并将其重写为 Ruby。

我的想法是启动一个将执行 python 脚本的进程,并在不再需要时终止该进程。

我启动进程如下,所以我可以访问它的pid:

def start
    ...
    @@pids[ object.id ] = IO.popen("python ./python_script_name.py").pid
    ...

@@pids 是一个散列,它存储所有启动进程的 pids,键为 object.id(假设每个对象只能启动一个进程)

当我想关闭连接时,我会像这样终止进程:

def stop
    ...
    pid = @@pids[ object.id ]
    system("kill #{pid}")

这导致僵尸进程(在ps aux | grep python之后可见):

[python] <defunct>

我试图将 SIGCHLD 信号发送到 rails 应用程序(因为它是之前调用的 python 脚本的父级)但它不起作用。

我想补充一点,我可能需要经常 call/kill 这个过程,所以它会导致大量的僵尸进程。

如何在不留下僵尸进程的情况下终止进程?

问题不在 python 脚本中 - 默认情况下可以正确处理信号(实施 signal 模块后没有变化)。

问题出在 ruby 脚本中。终止进程后,其父进程(在本例中为 rails 服务器)需要以某种方式知道它已被终止。为此,有一个 wait 函数。来自 ruby 文档:

The parent process should use Process.wait to collect the termination status of its child

因此,要正确处理杀死子进程,需要遵循:

def stop
    ...
    pid = @@pids[ object.id ]
    Process.kill( 15, pid )
    Process.wait( pid )
    ...