ruby - tiempos de espera de rubí y comandos del sistema
process timeout (4)
Creo que tienes que kill
manualmente:
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
Tengo un tiempo de espera de rubí que llama a un comando del sistema (bash) como este ...
Timeout::timeout(10) {
`my_bash_command -c12 -o text.txt`
}
pero creo que incluso si se interrumpe el hilo de rubí, el comando real sigue ejecutándose en segundo plano ... ¿es normal? ¿Cómo puedo matarlo?
El manejo de procesos, señales y temporizadores no es muy fácil. Es por eso que podría considerar delegar esta tarea: use el timeout
de timeout
del comando en las nuevas versiones de Linux:
timeout --kill-after 5s 10s my_bash_command -c12 -o text.txt
Quizás esto ayude a alguien más que busca lograr una funcionalidad de tiempo de espera similar, pero necesita recopilar la salida del comando de shell.
He adaptado el método de @shurikk para trabajar con Ruby 2.0 y algunos códigos del proceso hijo de Fork con tiempo de espera y captura de salida para recopilar la salida.
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
para detener adecuadamente el árbol de proceso generado (no solo el proceso padre), se debe considerar algo como esto:
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
Esto también le permite hacer un seguimiento del estado del proceso