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

如何处理(或防止)来自ruby反引号调用的SIGCHLD信号?,ruby,Ruby,我有一个长时间运行的进程,其中包含一些子进程,如果它们退出,则必须重新启动这些子进程。为了处理这些子进程的干净重启,我使用 trap("CLD") do cpid = Process.wait ... handle cleanup ... end 长时间运行的流程偶尔需要使用backquote调用“curl”,如中所示 `/usr/bin/curl -m 60 http://localhost/central/expire` 问题是,backquote调用导致我得到一个SIGCHLD

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

trap("CLD") do
  cpid = Process.wait
  ... handle cleanup ...
end
长时间运行的流程偶尔需要使用backquote调用“curl”,如中所示

`/usr/bin/curl -m 60 http://localhost/central/expire`
问题是,backquote调用导致我得到一个SIGCHLD并触发陷阱。然后,由于Process.wait没有完成,这会卡在CLD陷阱中。如果当时恰好没有(非反引号)子进程,则Process.wait会给出一个Errno::ECHILD异常

我可以通过在以下情况之前使用这一行包装反向报价调用来避免此问题:

sig_handler = trap("CLD", "IGNORE") #  Ignore child traps
在backquote调用之后的这一行:

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}"
从子流程启动受监视的子流程 只需从主进程的子进程开始跟踪和监视子进程,该子进程永远不会退出。这样它就不会注意到backtick子项退出

如果您这样做,您可以完全避免使用SIGCHLD,因为您可以使用一个带有等待的循环来通知子退出事件

其他想法:

  • 每次执行backtick命令时忽略一个SIGCHLD。我的意思是,你可能会以这种方式意外地忽略一个“真实的”信号,但这并不重要,因为你会得到一个“虚假的”信号,你会处理它

谢谢,但为了进一步说明,主进程位于轮询循环中,使用这些子进程与其他机器进行通信。子进程实际上是ssh客户机,它们通过隧道执行drb通信。因此,主要的过程不是坐在那里等待重新启动失败的孩子(尽管发生这种情况时必须这样做)。。。。。。然而,我认为你的想法可能会发生逆转。如果我从分叉的子进程启动curl的backtick调用,我应该能够阻止main(父进程)从backtick完成接收SIGCHLD的进程。我认为在这种情况下您仍然会得到SIGCHLD。您是对的,但是分叉进程似乎发送了一个SIGCHLD,其效果是process.wait in my CLD trap不会阻塞(如果我有其他子进程)或返回ECHILD(如果我没有其他子进程)。使用backtick,我要么坚持Process.wait,要么获取Errno::ECHILD异常。我还发现,使用spawn而不是backtick同样可以解决这个问题。我将在回答这个问题时显示示例代码。