Project: springxd
Issue XD-1291: Handle container shutdown gracefully
Currently, ModuleDeployer is a disposable bean. When the container context is closed, the ModuleDeployer bean is destroyed along with its associated common context and deployed modules. Issue arises, if the connectionfactory bean associated with the deployed modules' message bus bindings is destroyed before the ModuleDeployer bean, there is exception stacktrace (at least in case of Redis MessageBus) saying "Connection closed". Adding SmartLifecycle support to ModuleDeployer will make sure all the beans are destroyed during Lifecycle processor's stop() method before any of the singletonbeans are destroyed. The stacktrace (when using Redis MessageBus is): org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is com.lambdaworks.redis.RedisException: Connection closed at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:45) at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:35) at org.springframework.data.redis.connection.lettuce.LettuceConverters.toDataAccessException(LettuceConverters.java:158) at org.springframework.data.redis.connection.lettuce.LettuceConnection.convertLettuceAccessException(LettuceConnection.java:237) at org.springframework.data.redis.connection.lettuce.LettuceConnection.bRPop(LettuceConnection.java:1449) at org.springframework.data.redis.core.DefaultListOperations$12.inRedis(DefaultListOperations.java:154) at org.springframework.data.redis.core.AbstractOperations$ValueDeserializingRedisCallback.doInRedis(AbstractOperations.java:50) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:181) at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:149) at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:84) at org.springframework.data.redis.core.DefaultListOperations.rightPop(DefaultListOperations.java:151) at org.springframework.data.redis.core.DefaultBoundListOperations.rightPop(DefaultBoundListOperations.java:92) at org.springframework.integration.redis.inbound.RedisQueueMessageDrivenEndpoint.popMessageAndSend(RedisQueueMessageDrivenEndpoint.java:178) at org.springframework.integration.redis.inbound.RedisQueueMessageDrivenEndpoint.access$300(RedisQueueMessageDrivenEndpoint.java:51) at org.springframework.integration.redis.inbound.RedisQueueMessageDrivenEndpoint$ListenerTask.run(RedisQueueMessageDrivenEndpoint.java:291) at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:52) at java.lang.Thread.run(Thread.java:722) Caused by: com.lambdaworks.redis.RedisException: Connection closed at com.lambdaworks.redis.RedisAsyncConnection.await(RedisAsyncConnection.java:1079) at com.lambdaworks.redis.RedisConnection.await(RedisConnection.java:820) at com.lambdaworks.redis.RedisConnection.brpop(RedisConnection.java:101) at org.springframework.data.redis.connection.lettuce.LettuceConnection.bRPop(LettuceConnection.java:1447) ... 12 more 13:19:00,897 WARN Thread-5 support.DefaultLifecycleProcessor:257 - Failed to stop bean 'org.springframework.integration.redis.inbound.RedisInboundChannelAdapter#0' com.lambdaworks.redis.RedisException: Connection is closed at com.lambdaworks.redis.RedisAsyncConnection.dispatch(RedisAsyncConnection.java:1065) at com.lambdaworks.redis.pubsub.RedisPubSubConnection.unsubscribe(RedisPubSubConnection.java:82) at org.springframework.data.redis.connection.lettuce.LettuceSubscription.doUnsubscribe(LettuceSubscription.java:68) at org.springframework.data.redis.connection.util.AbstractSubscription.unsubscribe(AbstractSubscription.java:186) at org.springframework.data.redis.connection.util.AbstractSubscription.unsubscribe(AbstractSubscription.java:146) at org.springframework.data.redis.listener.RedisMessageListenerContainer$SubscriptionTask.cancel(RedisMessageListenerContainer.java:836) at org.springframework.data.redis.listener.RedisMessageListenerContainer.stop(RedisMessageListenerContainer.java:210) at org.springframework.integration.redis.inbound.RedisInboundChannelAdapter.doStop(RedisInboundChannelAdapter.java:127) at org.springframework.integration.endpoint.AbstractEndpoint.stop(AbstractEndpoint.java:100) at org.springframework.integration.endpoint.AbstractEndpoint.stop(AbstractEndpoint.java:115) at org.springframework.context.support.DefaultLifecycleProcessor.doStop(DefaultLifecycleProcessor.java:229) at org.springframework.context.support.DefaultLifecycleProcessor.access$300(DefaultLifecycleProcessor.java:51) at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.stop(DefaultLifecycleProcessor.java:363) at org.springframework.context.support.DefaultLifecycleProcessor.stopBeans(DefaultLifecycleProcessor.java:202) at org.springframework.context.support.DefaultLifecycleProcessor.onClose(DefaultLifecycleProcessor.java:118) at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:888) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.doClose(EmbeddedWebApplicationContext.java:157) at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:809)
Story points: 2