问题描述
我想正确地停止一个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);
});
}
这允许您静默关闭侦听器,并且自定义踏步会等待所有线程完成执行