From: Eric Wong Date: 2011-05-13T08:13:54+09:00 Subject: [ruby-core:36162] Re: [Ruby 1.9 - Bug #4681][Open] Timeout.timeout doesn't actually time out? mathew murphy wrote: > This doesn't actually seem to be what it does. > > Example code: > > #!/usr/bin/ruby > # encoding: UTF-8 > > require 'open3' > require 'timeout' > > puts "Time out after 2 seconds. Count them..." > result = Timeout.timeout(2) do > stdin, stdout, stderr = Open3.capture3("sleep 30") > output = stdout.read + "\n" + stderr.read > end > On my systems, this doesn't time out after 2 seconds. Instead, it runs > for 30 seconds, and then throws an error saying it took longer than 2 > seconds. It's because open3 has an ensure block where it does Thread#join and that waits forever, so the timeout thread raised to unblock the main thread, and then it got stuck again inside the ensure block. diff --git a/lib/open3.rb b/lib/open3.rb index b65cb19..d335f9f 100644 --- a/lib/open3.rb +++ b/lib/open3.rb @@ -207,6 +207,7 @@ module Open3 begin return yield(*result) ensure + p [ :ensure, __FILE__, __LINE__ ] parent_io.each{|io| io.close unless io.closed?} wait_thr.join end @@ -702,6 +703,7 @@ module Open3 begin return yield(*result) ensure + p [ :ensure, __FILE__, __LINE__ ] parent_io.each{|io| io.close unless io.closed?} wait_thrs.each {|t| t.join } end You can work around it by having an extra timeout block (ugly): --------------------------------------------------------- puts "Time out after 2 seconds. Count them..." Timeout.timeout(2) do result = Timeout.timeout(2) do stdin, stdout, stderr = Open3.capture3("sleep 30") output = stdout.read + "\n" + stderr.read end end But IMHO, timeout is a very fragile module and shouldn't be relied on. -- Eric Wong