# this is a race condition from - http://github.com/defunkt/cijoe/ # status = Open4.popen4(runner_command) do |pid, stdin, stdout, stderr| build.pid = pid write_build 'current', build err, out = stderr.read.strip, stdout.read.strip # < child process blocks when this becomes full # ^ # ^ # ^ # ^ we read stderr first, synchronously, while stdout is # ^ filling up with PIPE_MAX - causing the producing child # ^ process to hang - now our call to reading stderr will # ^ never return since the child is won't send EOF until it can # ^ finish sending stdout - which it is blocked on end # there is no way to read stdout/stderr of a child process, in ruby or any # other language, without risking a child process hang unless you # # 1) use select on *all of* stdout/stderr/stdin # # 2) use threads to write/read all three at once # # open4 implements #2 for you as Open4.spawn see # http://github.com/ahoward/open4/blob/master/samples/spawn.rb # for the above usage it'd be much simpler to use systemu - which cannot # process streams in realtime, but saves the user from having to consider the # intricacies of dealing with 3 streams. it also works on any platform, # including windows. the above code could be written safely and simply using # systemu as # status, stdout, stderr = systemu(runner_command) do |pid| build.pid = pid write_build('current', build) end