【问题标题】:Can't send signals to process created by PTY.spawn() in Ruby无法向 Ruby 中 PTY.spawn() 创建的进程发送信号
【发布时间】:2017-08-01 04:30:19
【问题描述】:

我在 Alpine docker 容器中运行 ruby​​(如果重要的话,它是一个 sidekiq 工作者)。在某个时刻,我的应用程序接收到指令以发送到子命令。我需要能够流式传输 STDOUT 而不是让它缓冲。这就是我使用 PTY 而不是 system() 或其他类似答案的原因。我正在执行以下代码行:

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

当我连接到 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

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

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

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

Process.kill('USR1', pid)

它将 USR1 发送到 sh,而不是 my_cmd,因此它的行为不正常。

有什么方法可以得到与我实际指定的命令相对应的 pid 吗?我对 PTY 领域之外的想法持开放态度,但它需要满足以下限制:

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

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

【问题讨论】:

    标签: ruby signals pty


    【解决方案1】:

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

    pgrep -P #{pid}
    

    获取子 pid,然后我可以将 USR1 发送到该进程。感觉很老套,但是当 ruby​​ 给你柠檬时......

    【讨论】:

    • pgrep 不是 ruby​​ 命令,顺便说一下。我不得不再次掏钱才能得到它。
    【解决方案2】:

    您应该将参数作为数组发送。所以不是

    stdout, stdin, pid = PTY.spawn("my_cmd arg1 arg2")
    

    你应该使用

    stdout, stdin, pid = PTY.spawn("my_cmd", "arg1", "arg2")
    

    等等

    另见:

    Process.spawn child does not receive TERM

    https://zendesk.engineering/running-a-child-process-in-ruby-properly-febd0a2b6ec8

    【讨论】:

      猜你喜欢
      • 2011-04-16
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      • 2016-03-21
      • 2017-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多