📖

[Bug #21456] IO#close が特定のタイミングだとプロセスが終了しないバグ報告

に公開

[Bug #21456] IO.close does not work in a rescue IO::TimeoutError block.

  • IO#close を呼び出すと強制的にプロセスが終了することを期待する
  • しかし IO::TimeoutError が発生し、そのタイミングで #close を呼び出してもプロセスは終了せず、待ち処理が発生してしまうというバグ報告
# 10秒の sleep を行うプロセスを作成
execArg = 'echo testwrite; sleep 10'
tofuProcess = IO.popen(execArg, 'r')

# 5秒でタイムアウトするような設定をする
puts 'executed tofu process.'
tofuProcess.timeout = 5

begin
  # プロセスを実行
  tofuOut = tofuProcess.read

  # 5秒経った段階でタイムアウトが発生して IO::TimeoutError が発生する
rescue IO::TimeoutError
  puts 'rescue occured'

  # IO::TimeoutError が発生したら即 #close を呼び出しプロセスを終了したい
  # しかし、これが即時で終了せずにプロセスの待ち処理が発生する
  tofuProcess.close

  puts 'process closed'
end
  • これなんですが実際には IO#close ではプロセスへシグナルを送ることはしておらずプロセスを終了させる場合は自分でシグナルを送る必要がある
  • 例えば以下のような対応をすることでやりたいことが実現できるみたいですね
execArg = 'echo testwrite; sleep 10'
# 孫プロセスから呼び出すので pgroup: を設定しておく必要がある
tofuProcess = IO.popen(execArg, 'r', pgroup: true)

puts 'executed tofu process.'
tofuProcess.timeout = 5

begin
  tofuOut = tofuProcess.read
rescue IO::TimeoutError
  puts 'rescue occured'

  # ここで対象のプロセスを終了する新ぐなるを送る
  Process.kill "-TERM", tofuProcess.pid
  tofuProcess.close

  puts 'process closed'
end
GitHubで編集を提案

Discussion