如何处理(或阻止)来自ruby反引号调用的SIGCHLD信号?

时间:2009-09-29 22:47:18

标签: ruby

我有一个长时间运行的进程,其中有一些子进程,如果它们退出就必须重新启动。为了处理这些子进程的干净重启,我用

捕获了退出信号
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}"

1 个答案:

答案 0 :(得分:1)

从子进程

启动受监视的子进程

只需从您的主要流程中永远不会退出的孩子开始跟踪和监控的孩子。这样就不会注意到那些反击的孩子们会离开...

如果你这样做,你可以完全避免使用SIGCHLD,因为你可以使用一个等待的循环来注意孩子退出事件。

其他想法:

  • 每次执行反引号命令时都忽略一个SIGCHLD。 ISTM你可能会以这种方式偶然忽略一个“真正的”SIGCHLD,但这并不重要,因为你会得到一个你将要处理的“假的”。