我有一个包含IO.popen调用的Ruby脚本。我可以用CTRL + C取消popen调用(我使用Signal.trap("SIGINT")
,然后导致我调用kill -2 #{popen_pid}
)。这很好用,当我按下CTRL + C时,kill -2
会导致popen进程在结束之前运行一些清理。
我的问题:当popen进程耗时太长时,我也希望能够有这种相同的行为。但是,我无法模拟CTRL + C行为。在ruby脚本的pid上使用Process.kill
最终只是在没有清理的情况下结束所有事情,并且在popen进程上运行Process.kill
什么都不做。我尝试使用反引号直接访问shell,在ruby脚本的pid和popen pid上调用kill -2
,但那些也没有做任何事情。
有人有任何建议吗?
答案 0 :(得分:0)
可能很难得到关于杀死进程的答案,尤其是在访问shell时。一个平台上的解决方案可能无法在其他平台上运行。我建议使用Timeout,而不是试图通过杀死你的进程的麻烦,如果你的IO.popen调用需要的时间比你想要的长,那么你可以在救援中进行清理。
require 'timeout'
seconds_to_wait = 10
begin
block_result = Timeout.timeout(seconds_to_wait) do
# your IO stuff
end
rescue Timeout::Error
puts "Ain't nobody got time for that!"
# do your clean up here
end
答案 1 :(得分:0)
事实证明我遇到的问题主要是因为我想在popen过程中打印行,因为他们正在发生这些行,但是还有一个超时会执行kill -2
来鼓励进程清理。
最后,我最终在popen调用旁边开始一个新线程(但是在我开始从命令开始打印之前),一旦popen调用花费的时间长于我的等待时间,线程就会调用kill -2
:
Thread.new do
$next_thread += 1
this_thread = $next_thread - 1
$active_threads[this_thread] = true
start_time = Time.now
while true
break if not $active_threads[this_thread]
minutes_elapsed = (Time.now - start_time) / 60
if minutes_elapsed > 90
inner_packer_pid = `ps -Af | tr -s ' ' | grep -v "grep" | grep "packer build" | cut -d' ' -f2 | sort | tail -n 1`.strip()
`kill -2 #{inner_packer_pid}`
cancel_build()
break
end
end
$active_threads[this_thread] = false
end
builders = Set.new
packer_build = IO.popen("packer build -color=#{not $is_no_color} #{spec_file} 2>&1")
$packer_build_pid = packer_build.pid
packer_build.each do |line|
puts line
end