Ruby 守护进程实现优雅关闭

7

我想制作一个Ruby守护进程,可以使用kill命令优雅地关闭。 我想添加一个信号陷阱,在关闭之前等待#可能需要一些时间运行的代码完成。 我该如何将其添加到类似于以下内容的代码中:

pid = fork do
   pid_file = "/tmp/pids/daemon6.pid"
   File.open(pid, 'w'){ |f| f.write(Process.pid) }
   loop do
      begin
         #code that could take some time to run
      rescue Exception => e
         Notifier.deliver_daemon_rescued_notification(e)
      end
      sleep(10)
   end
end
Process.detach pid

此外,将其放在一个单独的脚本中,例如一个单独的kill脚本,而不是将其作为守护进程代码的一部分,会更好吗?就像monitGod会调用停止它的东西?
非常感谢任何建议。
1个回答

7
您可以像这样捕获Interrupt
pid = fork do
  begin
    loop do
      # do your thing
      sleep(10)
    end
  rescue Interrupt => e
    # clean up
  end
end
Process.detach(pid)

您可以使用Signal.trap('INT') { ... }实现相同的功能,但由于涉及到sleep,我认为捕获异常更容易。

更新:这是一种更传统的方法,并确保循环在停止之前始终完成一个完整的操作:

pid = fork do
  stop = false
  Signal.trap('INT') { stop = true }
  until stop
    # do your thing
    sleep(10)
  end
end

缺点是它总是会执行sleep,因此在您杀死进程后,进程停止之前几乎总会有延迟。您可以通过分段休眠或进行各种变体的组合(仅在sleep周围保存Interrupt等)来解决这个问题。


谢谢你的回复,Theo。问题在于捕获中断不会让主循环结束。我想要做的是捕获中断,如果已经开始,则让循环完成,然后清理并终止进程。 - fflyer05
我已经更新了我的答案,提供了另一种更优雅的方法(但是使用 sleep 存在问题)。 - Theo
做得很好。谢谢!如果将sleep调用从until循环中移除会怎样?我认为Ruby的sleep已经是突发性的了,所以INT信号应该会将其唤醒。无论如何,额外的sleep比在循环中间停止进程要小得多。 - fflyer05
1
使用 guard sleep with if !stop,这样如果在工作时出现中断,它就不会进入睡眠状态并立即停止循环。那么剩下的问题就是在睡眠时发生中断 - 我不知道它是否会打破睡眠状态。 - Tomasz Stanczak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接