正确停止SpringBoot jmsApplication

问题描述

我想正确地停止一个jms应用程序,我有以下代码,我在侦听器中调用shutdown方法

   public void initiateAppShutDown(int returnCode){
        SpringApplication.exit(context,()-> returnCode);
   }
    
   public void shudDownApplication(){
        LOGGER.debug("Arret de l'application injecteur");
        initiateAppShutDown(0);
   }

我正在从侦听器的方法onMessageReceived()执行关闭,但是我有以下警告,似乎是从侦听器拒绝了消息:

Failed to shut down 1 bean with phase value 2147483647 within timeout of 30000: [org.springframework.jms.config.internalJmsListenerEndpointRegistry]

以及以下内容

DefaultMessageListenerContainer:由于在此期间侦听器容器已停止,因此拒绝接收到的消息:

更新

这是我的抗辩声明

// we increment the counter. incrementer nombre de messages traités
final AtomicInteger counter = new AtomicInteger(0); 

incrementCounter()方法递增counter

public void incrementCounter() {
    counter.getAndIncrement();
}

public int get() {
    return counter.get();
}

这是调用关机的方法

private void checkNumberMessagesProcessed() {
    if(this.get() == Integer.parseInt(nbrMaxMessages)){
        LOGGER.debug("fin de traitement reprise backout avec nombre de messages traites:  " + this.get());
        //close listeners
        //shutdown();
        //close application
        shudDownApplication();
    }
}

即使我已达到nbrMaxMessages=1000的参数设置,我仍然可以处理消息,并且应用程序会自动重启:这是日志:

2020-09-18 11:59:34,702 DEBUG --- [Backout-1-2] g.c.s.b.c.GdrBackoutListener             : end  process  backout with number of treated messages :  1000
2020-09-18 11:59:34,704 DEBUG --- [Backout-1-9] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304740080b5f1487913fe5270000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,705 DEBUG --- [Backout-1-5] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045f0080b5f08647b4ab6760000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,705 DEBUG --- [Backout-1-3] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304740080b5f116d7b4de1960000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,705 DEBUG --- [Backout-1-4] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304750080b5f136b3193b7690000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,708 DEBUG --- [pool-7-thread-1] g.c.s.b.c.GdrBackoutListener             : Shutdown application injecteur backout
2020-09-18 11:59:34,709 DEBUG --- [Backout-1-4] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045f0080b5f14f4120ec5b60000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,709 DEBUG --- [Backout-1-3] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045f0080b5f14003c676edb0000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,711 DEBUG --- [Backout-1-5] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304750080b5f1394ecc8bc480000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,711 DEBUG --- [Backout-1-2] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045f0080b5f15042af6ac7b0000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,712 DEBUG --- [Backout-1-8] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045b0080b5f150c84093cf60000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,712 DEBUG --- [ackout-1-10] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045b0080b5f0887a7225de50000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,714 DEBUG --- [Backout-1-3] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304730080b5f1649ac4348a70000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,714 DEBUG --- [Backout-1-4] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304730080b5f14fffe80e4a10000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,716 DEBUG --- [Backout-1-5] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304740080b5f146dee9feec60000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,716 DEBUG --- [Backout-1-2] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045b0080b5f158b80eac21f0000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,718  INFO --- [pool-7-thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@53dbe163: startup date [Fri Sep 18 11:59:32 CEST 2020]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@7a5ceedd
2020-09-18 11:59:34,719 DEBUG --- [Backout-1-3] g.c.s.b.c.GdrBackoutListener             : inject message 495853213045b0080b5f08b16224e18f0000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,720 DEBUG --- [Backout-1-4] g.c.s.b.c.GdrBackoutListener             : inject message 495853213047e0080b5f16b62be157e60000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,721 DEBUG --- [Backout-1-5] g.c.s.b.c.GdrBackoutListener             : inject message 49585321304730080b5f15dd2ce0d2df0000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,721 DEBUG --- [Backout-1-2] g.c.s.b.c.GdrBackoutListener             : inject message 495853213047e0080b5f084d3a3b00260000000000000000 dans INTERNAL_QUEUE with number of messages to trate to 1000
2020-09-18 11:59:34,723  INFO --- [pool-7-thread-1] o.s.c.s.DefaultLifecycleProcessor        : Stopping beans in phase 2147483647

解决方法

您正在同一线程中触发一次关闭调用,就像死锁一样,您的onMessage方法正在等待关闭,而JMS容器正在等待正在运行的任务终止,并且最终会超时。

要解决此问题,您可以使用一个异步执行程序来触发关机,诸如此类。

@Component
public class MessageListener {
   ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
   @JmsListener(...)
   public void onShutdownMessage(Message message){
       // increase delay further if observer any issue,it will trigger shutdown call in 1 seconds
       executorService.schedule(() -> {shudDownApplication();},1,TimeUnit.SECONDS);
   }
}
,

最终我解决了这个问题。

我对我的监听器有周期性的依赖。

我试图让侦听器在等待所有线程完成工作后停止运行。

这是不正确的方法。所以我创建了一个错误处理程序,然后从JmsListener抛出错误。并通过shutdownManager类管理关闭。 在shutDownManager中,我创建了一个新线程来停止springApplication。 对于线程并发上下文,此方法很好用。这是代码:

@Component
public class AppContextManager implements ApplicationContextAware {
       private static ApplicationContext _appCtx;

    @Override
    public void setApplicationContext(ApplicationContext ctx){
         _appCtx = ctx;
    }

    public static ApplicationContext getAppContext(){
        return _appCtx;
    }

    public static void exit(Integer exitCode) {
        System.exit(SpringApplication.exit(_appCtx,() -> exitCode));
    }

    }

在错误处理程序中,当您想关闭您的应用程序时,您会捕获到Jmslistener引发的异常,请调用此方法

private void shutDown(){
//JmsListenerEndpointRegistry bean = context.getBean(JmsListenerEndpointRegistry.class);
ExecutorService executorService = Executors.newSingleThreadExecutor();

    executorService.execute(() -> {
        //bean.stop();
        appContext.exit(0);
    });

}

这允许您静默关闭侦听器,并且自定义踏步会等待所有线程完成执行