【问题标题】:How can I handle (or prevent) SIGCHLD signals from ruby backquote invocations?如何处理(或防止)来自 ruby​​ 反引号调用的 SIGCHLD 信号?
【发布时间】:2009-10-01 07:01:02
【问题描述】:

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

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

【问题讨论】:

    标签: ruby


    【解决方案1】:

    从子进程启动被监控的子进程

    只需从永远不会退出的主进程的子进程开始跟踪和监控子进程。这样它就不会注意到退出的反引号孩子......

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

    其他想法:

    • 每次执行反引号命令时忽略一个 SIGCHLD。 ISTM,您可能会以这种方式意外忽略“真实”SIGCHLD,但这没关系,因为您会得到一个“虚假”的信号进行处理。

    【讨论】:

    • 谢谢,但要提供更多详细信息,主进程处于轮询循环中,该循环使用这些子进程与其他机器进行通信。子进程实际上是 ssh 客户端,它们创建隧道,通过这些隧道执行 drb 通信。因此,主要过程不仅仅是坐等重启失败的子进程(尽管发生这种情况时必须这样做)......
    • ... 但是,我认为颠倒您的想法可能是有希望的。如果我从分叉的子进程启动 curl 的反引号调用,我应该能够防止主(父)进程从反引号完成接收 SIGCHLD。
    • 我认为在这种情况下你仍然会得到 SIGCHLD。
    • 你是对的,但是分叉​​的进程似乎发送了一个 SIGCHLD,其效果是我的 CLD 陷阱中的 Process.wait 不会阻塞(如果我有其他孩子)或返回 ECHILD(如果我没有有其他孩子)。使用反引号我要么坚持 Process.wait 获得 Errno::ECHILD 异常。我还发现使用 spawn 而不是反引号可以以同样的方式解决问题。我将在对此的答案中显示示例代码。
    猜你喜欢
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多