Timeout a Subprocess in Ruby
March 30 2012 12:30 CET
Spawning of a long running process in Ruby can cause you some problems if you want to set a timeout.
For example consider the following:
pipe = IO.popen("long_running_program")
Process.wait pipe.pid
Now the Process.wait call will cause our Ruby script to block while waiting for it’s child to finish.
Enter Timeout – a native module in Ruby.
We can now do something like this:
require 'timeout'
begin
Timeout.timeout(30) do
@pipe = IO.popen("long_running_program")
Process.wait @pipe.pid
end
rescue Timeout::Error
Process.kill 9, @pipe.pid
end
Better. But now we have a problem. Since we do not collect the child’s status after it finished (was killed) the kernel will hang on to that information and you’ll see the child process as a zombie (“Z” if you run ps aux).
So, we need to collect that info using Process.wait (it’ll finish immediately since the process was killed), like so:
require 'timeout'
begin
Timeout.timeout(30) do
@pipe = IO.popen("long_running_program")
Process.wait @pipe.pid
end
rescue Timeout::Error
Process.kill 9, @pipe.pid
Process.wait @pipe.pid # we need to collect status so it doesn't stick around as zombie process
end
And that is a quick solution to killing off child processes via a timeout.