杀死在ruby中使用open3调用的进程

时间:2014-10-09 00:22:03

标签: ruby popen3

我正在使用命令行程序,它的工作原理如下:

$ ROUTE_TO_FOLDER/app < "long text"

如果“长文字”是使用“app”需要的参数编写的,那么它会填充带有结果的文本文件。如果没有,它将连续填充文本文件中的点(我无法处理或修改“app”的代码以避免这种情况)。

在ruby脚本中有一行如下:

text = "long text that will be used by app"
output = system("ROUTE_TO_FOLDER/app < #{text}")

现在,如果文字写得很好,就不会有问题,我会得到一个如前所述的输出文件。文本写得不好时会出现问题。接下来发生的事情是我的ruby脚本挂起,我不知道如何杀死它。

我找到Open3并且我使用了这样的方法:

irb> cmd = "ROUTE_TO_FOLDER/app < #{text}"
irb> stdin, stdout, stderr, wait_thr = Open3.popen3(cmd)
=> [#<IO:fd 10>, #<IO:fd 11>, #<IO:fd 13>, #<Thread:0x007f3a1a6f8820 run>]

当我这样做时:

irb> wait_thr.value

它也挂了,并且:

irb> wait_thr.status
=> "sleep"

所以......¿我该如何避免这些问题? ¿是不是认识到“app”失败了?

提前致谢

1 个答案:

答案 0 :(得分:6)

wait_thr.pid为您提供已启动流程的pid。只是做

Process.kill("KILL",wait_thr.pid)

当你需要杀死它时。

您可以将其与检测过程是否挂起(连续输出点)以两种方式之一进行组合。

1)设置等待进程的超时时间:

get '/process' do
  text = "long text that will be used by app"
  cmd = "ROUTE_TO_FOLDER/app < #{text}"
  Open3.popen3(cmd) do |i,o,e,w|
    begin
      Timeout.timeout(10) do # timeout set to 10 sec, change if needed
        # process output of the process. it will produce EOF when done.
        until o.eof? do
          # o.read_nonblock(N) ...
        end
      end
    rescue Timeout::Error
      # here you know that the process took longer than 10 seconds
      Process.kill("KILL", w.pid)
      # do whatever other error processing you need
    end
  end
end

2)检查过程输出。 (下面的代码是简化的 - 您可能不希望首先将进程的输出读入单个字符串buf然后进行处理,但我想你明白了。)

get '/process' do
  text = "long text that will be used by app"
  cmd = "ROUTE_TO_FOLDER/app < #{text}"
  Open3.popen3(cmd) do |i,o,e,w|
    # process output of the process. it will produce EOF when done. 
    # If you get 16 dots in a row - the process is in the continuous loop
    # (you may want to deal with stderr instead - depending on where these dots are sent to)
    buf = ""
    error = false
    until o.eof? do
      buf << o.read_nonblock(16)
      if buf.size>=16 && buf[-16..-1] == '.'*16
        # ok, the process is hung
        Process.kill("KILL", w.pid)
        error = true
        # you should also get o.eof? the next time you check (or after flushing the pipe buffer),
        # so you will get out of the until o.eof? loop
      end
    end
    if error
      # do whatever error processing you need
    else
      # process buf, it contains all the output
    end
  end
end