【问题标题】:ActiveRecord::StatementInvalid when process receives SIGTERM?进程收到 SIGTERM 时 ActiveRecord::StatementInvalid?
【发布时间】:2010-10-07 13:50:53
【问题描述】:

在我的 Rails 应用程序中,我有一个脚本可以更新数据库中的一些记录。当我发送 SIGTERM 来终止脚本时,它偶尔会在 ActiveRecord 执行查询时收到该信号。这会导致引发 ActiveRecord::StatementInvalid 异常。

我想捕获当它们是 SIGTERM 的结果时发生的 StatementInvalid 异常并退出脚本。如何判断 StatementInvalid 是由于信号而不是其他原因而发生的?

【问题讨论】:

  • 您还有什么要解决的问题吗?

标签: ruby-on-rails sigterm


【解决方案1】:

如果你捕获了 TERM 信号,我相信你会避免异常。您可以在脚本的开头执行此操作(或者实际上在任何地方执行此操作,但您只需执行一次)。

 Signal.trap("TERM") do
   Kernel.exit!
 end

您收到 StatementInvalid 错误的原因是 Ruby 通过在当前执行位置引发 SIGTERM 异常来处理信号。 ActiveRecord 正在捕获异常并将其作为 StatementInvalid 重新抛出。通过设置信号处理程序,Ruby 将执行您的处理程序而不是引发异常。

请参阅Ruby Signal documentation 了解更多信息。

【讨论】:

  • 已修复,必须使用 Kernel.exit!为此工作。举例证明:gist.github.com/66735
  • 假设这种类型的退出是“正常的”,你可能想要Kernel.exit! true。进程将以状态 0 退出的方式。
【解决方案2】:

听起来这个“脚本”在 Rails 应用程序的外部(script/runner 或类似的?),所以也许您可以解耦“信号处理程序”和“工作程序”?例如,您可以派生一个子进程/线程/光纤/... 来更新数据库,并向父进程发出信号以指示“现在停止”吗?当然,父母必须“通知”孩子停止使用某种适当的机制(不是SIGTERM ;-))。

【讨论】:

    【解决方案3】:

    这不是 OP 的确切答案,但是,您可以控制退出点 - 程序只有在到达您定义的退出点后才会退出。

    time_to_die=false
    
    # Prevent abrupt stopping of the daemon.
    Signal.trap("TERM") { time_to_die=true; "SIG_IGN" }   
    
    loop {
      .
      .
      exit_gracefully if time_to_die
      .
      .
    }
    
    def exit_gracefully
       #Cleaning up..
       $log.log "#{Time.now} TERM signal received. Exiting.."
       $db.close
       exit
     end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      • 2013-10-31
      • 2014-02-03
      • 2013-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多