我有一个长时间运行的进程,其中有一些子进程,如果它们退出就必须重新启动。为了处理这些子进程的干净重启,我用
捕获了退出信号trap("CLD") do
cpid = Process.wait
... handle cleanup ...
end
长时间运行的过程偶尔需要使用反引号调用'curl',如
`/usr/bin/curl -m 60 http://localhost/central/expire`
问题是反引用调用导致我获得SIGCHLD并使我的陷阱发生火灾。然后它会卡在CLD陷阱中,因为Process.wait没有完成。如果当时没有(非反引用)子进程,则Process.wait会给出Errno :: ECHILD异常。
我可以通过在此行之前用这一行包装反引号来解决这个问题:
sig_handler = trap("CLD", "IGNORE") # Ignore child traps
和反引用调用之后的这一行:
trap("CLD", sig_handler) # replace the handler
但这意味着我可能会错过该窗口中(非反引号)子进程的信号,所以我对此并不满意。
那么,有更好的方法吗? (如果重要的话,我在GNU / Linux 2.6.22.6上使用ruby 1.9.1p243)
更新: 下面的代码说明了问题(以及我目前的解决方案)。 这里似乎有一些奇怪的时间问题,因为我并不总是得到ECHILD异常。但只有一次就足以搞砸了。
#!/usr/bin/env ruby
require 'pp'
trap("CLD") do
cpid = nil
begin
puts "\nIn trap(CLD); about to call Process.wait"
cpid = Process.wait
puts "In trap(CLD); Noting that ssh Child pid #{cpid}: terminated"
puts "Finished Child termination trap"
rescue Errno::ECHILD
puts "Got Errno::ECHILD"
rescue Exception => excep
puts "Exception in CLD trap for process [#{cpid}]"
puts PP.pp(excep, '')
puts excep.backtrace.join("\n")
end
end
#Backtick problem shown (we get an ECHILD most of the time)
puts "About to invoke backticked curl"
`/usr/bin/curl -m 6 http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo`
sleep 2; sleep 2 # Need two sleeps because the 1st gets terminated early by the trap
puts "Backticked curl returns"
# Using spawn
puts "About to invoke curl using spawn"
cpid = spawn("/usr/bin/curl -m 6 http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo")
puts "spawned child pid is #{cpid} at #{Time.now}"
答案 0 :(得分:1)
只需从您的主要流程中永远不会退出的孩子开始跟踪和监控的孩子。这样就不会注意到那些反击的孩子们会离开...
如果你这样做,你可以完全避免使用SIGCHLD,因为你可以使用一个等待的循环来注意孩子退出事件。
其他想法: