【问题标题】:How do I cleanly shut down an embedded JRuby in response to a SIGTERM to the JVM process?我如何干净地关闭嵌入式 JRuby 以响应 JVM 进程的 SIGTERM?
【发布时间】:2015-04-16 15:00:00
【问题描述】:

我正在使用org.jruby.embed.ScriptingContainer API 在 JVM 进程内的 JRuby 上运行 Middleman(使用 Webrick)服务器。

如果我完全关闭并从 JVM 内部停止服务器,一切都会按预期工作。

但是,如果我向 JVM 进程发送 SIGTERM(例如,通过在命令行中按 ctrl+C),控制台会返回,但 JVM 进程不会终止——它会无限期地挂起,直到我向它发送 SIGKILL。

我尝试注册一个 JVM 关闭钩子来终止 ScriptingContainer 实例,但该钩子永远不会触发。我不知道为什么......也许 JRuby 正在以某种方式吞下 SIGTERM?

如何让 JVM 彻底关闭,即使它包含一个正在运行的 Webrick 服务器?

【问题讨论】:

  • 您是否验证了问题出在 JRuby 上,也许是通过将 ScriptingContainer 换成 org.jruby.embed.EmbedRubyInstanceConfigAdapter 的无操作实现并查看问题是否仍然存在?
  • Control-C 不发送 SIGTERM,它发送 SIGINT
  • 您使用的是什么操作系统?你可以在你按下 ctrl+c 之后提供一个 JVM 的线程转储吗? (运行jstack <pid>)如何检查您的关闭挂钩是否触发?
  • 在WEBrick documentation 之后,我读到它是因为 WEBrick 能够安装 SIGINT 处理程序。所以中间人会做这部分。也许你的问题的根源在不同的地方。您是否尝试过使用jconsole 连接到会话以检查哪个线程仍然处于活动状态。
  • 您是否创建了任何线程,或者 ScriptingContainer 是否创建了任何线程?

标签: java jvm jruby webrick


【解决方案1】:

看起来kill -9 不会触发shutdownHook,但kill -15 会。

This StackOverflow question 对同一问题有详细的解答。

底线是,你搞砸了,因为似乎不存在任何方法来拦截 kill -9 信号并在 JVM 停止之前执行一些维护任务。

【讨论】:

  • 信号手册页 ""信号 SIGKILL 和 SIGSTOP 不能被捕获、阻止或忽略。""",即使在 C 程序中也无法真正处理 sigkill。man7.org/linux/man-pages/man7/signal.7.html
  • 我不需要处理 SIGKILL... 这很好,因为它仍然会导致整个进程关闭。我的问题是检测并终止 SIGTERM 或 SIGINT。
  • SIGINT 和 SIGTERM 信号在 Linux 上被观察到,但在 Windows 中它从未将这些信号发送到应用程序。
【解决方案2】:

首先,一个调试技巧:您可以将SIGQUIT 发送到Java 进程,让它打印所有正在运行的线程的当前堆栈跟踪。这可以帮助您诊断哪些线程导致 JVM 无法退出。

发送 SIGINT、SIGHUP 或 SIGTERM 会导致 Java 运行其关闭挂钩,然后退出。您可以在java.lang.Terminator 中看到这一点。收到信号后,java.lang.Shutdown 会在终止进程之前处理运行所有关闭挂钩。 Shutdown.halt() 直到关闭挂钩全部完成后才会调用,这表明您有一个挂起的关闭挂钩。

如果没有实际的代码或堆栈跟踪,很难提供比这更精确的答案,但是在您发送 SIGINT 后仍保持活动状态的 JVM 通常会在其关闭挂钩中做一些奇怪的事情。如果这还不够,请尝试发送SIGINT,等待几秒钟,然后发送SIGQUIT,并将生成的堆栈跟踪添加到问题中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2014-03-22
    • 2014-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多