7

私はコマンドラインプログラムを使用していますが、以下のように動作します:

$ ROUTE_TO_FOLDER/app < "long text"

「アプリ」が必要とするパラメーターを使用して「長いテキスト」が書き込まれると、テキスト ファイルに結果が書き込まれます。そうでない場合は、テキスト ファイルを継続的にドットで埋めます (これを回避するために「アプリ」のコードを処理または変更することはできません)。

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"

これらの問題を回避するにはどうすればよいですか? 「アプリ」が失敗したことを認識していませんか?

4

1 に答える 1

10

wait_thr.pid開始されたプロセスの pid を提供します。やるだけ

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

あなたがそれを殺す必要があるとき。

2 つの方法のいずれかで、プロセスがハングしている (継続的にドットを出力する) かどうかを検出することと組み合わせることができます。

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) プロセスの出力を確認します。(以下のコードは簡略化されています。おそらく、プロセスの出力を最初に単一の String 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
于 2014-10-09T01:43:23.757 に答える