Kill a process called using open3 in ruby

◇◆丶佛笑我妖孽 提交于 2021-01-27 04:46:29

问题


I'm using a command line program, it works as mentioned below:

$ ROUTE_TO_FOLDER/app < "long text"

If "long text" is written using the parameters "app" needs, then it will fill a text file with results. If not, it will fill the text file with dots continuously (I can't handle or modify the code of "app" in order to avoid this).

In a ruby script there's a line like this:

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

Now, if text is well written, there won't be problems and I will get an output file as mentioned before. The problem comes when text is not well written. What happens next is that my ruby script hangs and I'm not sure how to kill it.

I've found Open3 and I've used the method like this:

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>]

When I do:

irb> wait_thr.value

it also hangs, and :

irb> wait_thr.status
=> "sleep"

How can I avoid these problems? Is it not recognizing that "app" has failed?


回答1:


wait_thr.pid provides you the pid of the started process. Just do

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

when you need to kill it.

You can combine it with detecting if the process is hung (continuously outputs dots) in one of the two ways.

1) Set a timeout for waiting for the process:

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) Check the process output. (The code below is simplified - you probably don't want to read the output of your process into a single String buf first and then process, but I guess you get the idea).

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


来源:https://stackoverflow.com/questions/26268454/kill-a-process-called-using-open3-in-ruby

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!