当进程收到 SIGTERM 时 ActiveRecord::StatementInvalid?

发布于 2024-07-13 11:28:57 字数 244 浏览 10 评论 0原文

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

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

In my Rails app, I have a script that updates some records in the database. When I send a SIGTERM to kill the script, it occasionally receives that signal while ActiveRecord is executing a query. This leads to an ActiveRecord::StatementInvalid exception being raised.

I'd like to catch StatementInvalid exceptions that occur when they're they're the result of a SIGTERM and exit the script. How can I tell that a StatementInvalid is occurring because of a signal and not for some other reason?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

末が日狂欢 2024-07-20 11:28:57

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

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

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

有关更多信息,请参阅 Ruby Signal 文档

If you trap the TERM signal, I believe you will avoid the exception. You can do this at the beginning of your script (or really anywhere for that matter, but you only need to do it once).

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

The reason you get the StatementInvalid error is Ruby handles the signal by raising a SIGTERM exception at the place of current execution. ActiveRecord is catching the exception and rethrowing it as StatementInvalid. By setting a Signal handler, Ruby will execute your handler instead of raising an exception.

See the Ruby Signal documentation for more information.

相思故 2024-07-20 11:28:57

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

It sounds like this "script" is external to the Rails app (script/runner or similar?), so perhaps you can decouple the "signal handler" and "worker"? Eg can you fork a child process/thread/fiber/... to do the database update, and signal the parent to indicate "stop now"? Of course the parent will then have to "signal" the child to stop using some appropriate mechanism (not SIGTERM ;-)).

梦中的蝴蝶 2024-07-20 11:28:57

这不是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

This is not an exact answer to the OP, however, you can control the exit point - the program will exit only after reaching the exit point defined by you.

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文