无法向Ruby中的PTY.spawn()创建的进程发送信号

时间:2022-07-16 21:03:52

I'm running ruby in an Alpine docker container (it's a sidekiq worker, if that matters). At a certain point, my application receives instructions to shell out to a subcommand. I need to be able to stream STDOUT rather than have it buffer. This is why I'm using PTY instead of system() or another similar answer. I'm executing the following line of code:

我正在一个阿尔卑斯码头工人的容器中运行红宝石(如果这很重要的话,那就是一个sidekiq工人)。在某个时刻,我的应用程序收到shell命令的命令。我需要能够传输STDOUT而不是缓冲区。这就是我使用PTY而不是system()或其他类似答案的原因。我正在执行以下代码行:

stdout, stdin, pid = PTY.spawn(my_cmd)

When I connect to the docker container and run ps auxf, I see this:

当我连接到docker容器并运行ps auxf时,我看到:

root         7  0.0  0.4 187492 72668 ?        Sl   01:38   0:00 ruby_program
root     12378  0.0  0.0   1508   252 pts/4    Ss+  01:38   0:00  \_ sh -c my_cmd
root     12380  0.0  0.0  15936  6544 pts/4    S+   01:38   0:00      \_ my_cmd

Note how the child process of ruby is "sh -c my_cmd", which itself then has a child "my_cmd" process.

注意ruby的子进程是如何“sh -c my_cmd”,它本身就有一个子进程“my_cmd”。

"my_cmd" can take a significant amount of time to run. It is designed so that sending a signal USR1 to the process causes it to save its state so it can be resumed later and abort cleanly.

“my_cmd”可能需要很长时间才能运行。它的设计使得向进程发送信号USR1使其保存其状态,以便以后可以恢复并干净地中止。

The problem is that the pid returned from "PTY.spawn()" is the pid of the "sh -c my_cmd" process, not the "my_cmd" process. So when I execute:

问题是从“PTY.spawn()”返回的pid是“sh -c my_cmd”进程的pid,而不是“my_cmd”进程。所以当我执行时:

Process.kill('USR1', pid)

it sends USR1 to sh, not to my_cmd, so it doesn't behave as it should.

它将USR1发送到sh,而不是my_cmd,因此它的行为不应该如此。

Is there any way to get the pid that corresponds to the command I actually specified? I'm open to ideas outside the realm of PTY, but it needs to satisfy the following constraints:

有没有办法获得与我实际指定的命令相对应的pid?我对PTY之外的想法持开放态度,但它需要满足以下约束:

1) I need to be able to stream output from both STDOUT and STDERR as they are written, without waiting for them to be flushed (since STDOUT and STDERR get mixed together into a single stream in PTY, I'm redirecting STDERR to a file and using inotify to get updates).

1)我需要能够在写入时从STDOUT和STDERR流式传输输出,而不必等待它们被刷新(因为STDOUT和STDERR混合在一起成为PTY中的单个流,我将STDERR重定向到文件并使用inotify获取更新)。

2) I need to be able to send USR1 to the process to be able to pause it.

2)我需要能够将USR1发送到进程才能暂停它。

1 个解决方案

#1


0  

I gave up on a clean solution. I finally just executed

我放弃了一个干净的解决方案。我终于刚刚执行了

pgrep -P #{pid}

to get the child pid, and then I could send USR1 to that process. Feels hacky, but when ruby gives you lemons...

得到孩子的pid,然后我可以将USR1发送到该过程。感觉hacky,但当红宝石给你柠檬...

#1


0  

I gave up on a clean solution. I finally just executed

我放弃了一个干净的解决方案。我终于刚刚执行了

pgrep -P #{pid}

to get the child pid, and then I could send USR1 to that process. Feels hacky, but when ruby gives you lemons...

得到孩子的pid,然后我可以将USR1发送到该过程。感觉hacky,但当红宝石给你柠檬...