简体   繁体   English

安全地终止Spring JMS应用程序

[英]Safely Terminating a Spring JMS application

I'm working on a Spring boot JMS application that is setup strictly with bean annotations and is reading messages from WebshpereMQ. 我正在开发一个Spring引导JMS应用程序,该应用程序严格使用bean注释进行设置,并且正在从WebshpereMQ中读取消息。 Everything works except I can't figure out how to safely shutdown this application. 一切正常,除了我无法弄清楚如何安全地关闭这个应用程序。 Once my JMSListener Method reads all the messages it just stays idle. 一旦我的JMSListener方法读取所有消息,它就会保持空闲状态。 I make an initial connection to the queue and access the queue depth, so ideally when queue depth is zero, it needs to wrap it up and shut down. 我建立了与队列的初始连接并访问队列深度,因此理想情况下,当队列深度为零时,需要将其包装起来并关闭。 My current workaround (and I do not like it at all) is this little method I call (from inside the listener, yikes ) when depth is zero: 我当前的解决方法(我根本不喜欢它)是我在深度为零时调用的一个小方法(来自侦听器内部, yikes ):

public void shutDownApplication() {
        logger.info("Initiating shutdown of application...");
        System.out.println("Terminating application...");
        Thread.currentThread().interrupt();
        System.exit(0);
    }

I do not like this solution. 我不喜欢这个解决方案。 And neither does Spring, because this is obviously interrupted as an error mid-process and before the application dies my JMSListener initiates a rollback and puts the single last remaining message back on the queue. Spring也没有,因为这显然是作为中间进程中的错误而中断,在应用程序死亡之前,我的JMSListener启动回滚并将单个最后剩余的消息放回队列。

I tried a few other solutions after looking at the following sources: 在查看以下来源后,我尝试了一些其他解决方案:

How can I Stop/start/Pause a @JmsListener (the clean way) 如何停止/启动/暂停@JmsListener(干净的方式)

How to gracefully shut down a Spring JMS MessageListenerAdapter 如何正常关闭Spring JMS MessageListenerAdapter

http://forum.spring.io/forum/spring-projects/integration/jms/124980-graceful-shutdown-of-jms-message-listener http://forum.spring.io/forum/spring-projects/integration/jms/124980-graceful-shutdown-of-jms-message-listener

This was my most recent solution: 这是我最近的解决方案:

public class JMSShutdownService {

    public void initiateShutdown() {
        JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry();
        Collection<MessageListenerContainer> col = jmsListenerEndpointRegistry
                .getListenerContainers();
        for (MessageListenerContainer cont : col) {
            cont.stop(Thread.currentThread());
        }
        System.exit(0);
    }

}

This kills the application but still puts the last message back on the queue. 这会终止应用程序,但仍会将最后一条消息放回队列中。 There are alot of intricacies of Spring I'm still trying to understand, so it all really comes down to that. 有很多错综复杂的Spring我还在努力去理解,所以这一切都归结为此。 I feel like the main issue is that it is inside the listener I signal for shutdown. 我觉得主要的问题是它在侦听器内部我发出关闭信号。 From what I gather the listener shouldn't be responsible for that. 从我收集的内容来看,听众不应对此负责。 But I'm not sure how to define a way to shutdown the application before the listener starts, or how to pop out of the listener when queue depth is zero. 但我不确定如何在侦听器启动之前定义关闭应用程序的方法,或者在队列深度为零时如何弹出侦听器。

Any ideas? 有任何想法吗?

JmsListenerEndpointRegistry jmsListenerEndpointRegistry = new JmsListenerEndpointRegistry();

That's no use; 那是没用的; a new registry won't have any containers, if you are using @JmsListener you need to get the registry from the application context. 新的注册表将没有任何容器,如果您使用@JmsListener ,则需要从应用程序上下文中获取注册表。

System.exit(0);

That just kills the JVM. 这只会杀死JVM。

The bottom line is you should stop on the container on a different thread - use a task executor to start a new thread to stop the container; 底线是你应该停在不同线程上的容器上 - 使用任务执行器来启动一个新线程来停止容器; the container will wait for the thread to exit the listener before stopping. 容器将在停止之前等待线程退出侦听器。

After stopping the container, you will need to wait for a grace period before killing the JVM. 停止容器后,您需要等待一段宽限期才能终止JVM。

How do you really know you are done? 你怎么知道你已经完成了? Another message could show up after you stop the container, in which case you'll likely see some noise in the log about a message being rejected because the container is stopping. 停止容器后,可能会显示另一条消息,在这种情况下,由于容器正在停止,您可能会在日志中看到有关消息被拒绝的噪音。

EDIT 编辑

in my listener... 在我的听众......

...
if (timeToShutDown()) {
    Executors.newSingleThreadExecutor.execute(new Runnable() {

        public void run() {
            stopTheContainer();
        }
    }
 }
 // exit the listener so the container can actually stop.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM