ruby timeouts and system commands

前端 未结 4 1852
傲寒
傲寒 2020-12-09 16:13

I have a ruby timeout that calls a system (bash) command like this..

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

but I th

相关标签:
4条回答
  • 2020-12-09 16:41

    Perhaps this will help someone else looking to achieve similar timeout functionality, but needs to collect the output from the shell command.

    I've adapted @shurikk's method to work with Ruby 2.0 and some code from Fork child process with timeout and capture output to collect the output.

    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
    
    0 讨论(0)
  • 2020-12-09 16:41

    Handling processes, signals and timers is not very easy. That's why you might consider delegating this task: Use the command timeout on new versions of Linux:

    timeout --kill-after 5s 10s my_bash_command -c12 -o text.txt
    
    0 讨论(0)
  • 2020-12-09 16:44

    I think you have to kill it manually:

    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
    
    0 讨论(0)
  • 2020-12-09 16:50

    in order to properly stop spawned process tree (not just the parent process) one should consider something like this:

    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
    

    this also allows you to track process status

    0 讨论(0)
提交回复
热议问题