ruby超时和系统命令

我有一个ruby超时,调用这样的系统(bash)命令..

Timeout::timeout(10) { `my_bash_command -c12 -o text.txt` } 

但我认为即使ruby线程被中断,实际命令仍然在后台运行..这是正常的吗? 我怎么能杀了它?

我想你必须手动kill它:

 require 'timeout' puts 'starting process' pid = Process.spawn('sleep 20') begin Timeout.timeout(5) do puts 'waiting for the process to end' Process.wait(pid) puts 'process finished in time' end rescue Timeout::Error puts 'process not finished in time, killing it' Process.kill('TERM', pid) end 

为了正确地停止衍生的进程树(不仅仅是父进程),你应该考虑这样的事情:

 def exec_with_timeout(cmd, timeout) pid = Process.spawn(cmd, {[:err,:out] => :close, :pgroup => true}) begin Timeout.timeout(timeout) do Process.waitpid(pid, 0) $?.exitstatus == 0 end rescue Timeout::Error Process.kill(15, -Process.getpgid(pid)) false end end 

这也允许您跟踪进程状态

也许这会帮助其他人寻求实现类似的超时function,但需要从shell命令收集输出。

我已经使用@ shurikk的方法来处理Ruby 2.0和来自Fork子进程的一些代码, 使用超时和捕获输出来收集输出。

 def exec_with_timeout(cmd, timeout) begin # stdout, stderr pipes rout, wout = IO.pipe rerr, werr = IO.pipe stdout, stderr = nil pid = Process.spawn(cmd, pgroup: true, :out => wout, :err => werr) Timeout.timeout(timeout) do Process.waitpid(pid) # close write ends so we can read from them wout.close werr.close stdout = rout.readlines.join stderr = rerr.readlines.join end rescue Timeout::Error Process.kill(-9, pid) Process.detach(pid) ensure wout.close unless wout.closed? werr.close unless werr.closed? # dispose the read ends of the pipes rout.close rerr.close end stdout end 

处理过程,信号和定时器并不是一件容易的事。 这就是为什么您可以考虑委派此任务:在新版本的Linux上使用命令timeout

 timeout --kill-after 5s 10s my_bash_command -c12 -o text.txt