Spring-boot: Shutdown Hazelcast

Created on 18 Nov 2016  路  4Comments  路  Source: spring-projects/spring-boot

Spring Boot automatically starts Hazelcast, but it does not shut it down when the application exits. As a result, the process does not exit because of the Hazelcast daemon threads. At first, I logged it as hazelcast/hazelcast#6339, but they feel it's not a Hazelcast issue and I agree with them.

To reproduce the issue, I have created a small repository: https://github.com/Bert-R/hazelcast-shutdown-issue. It contains a basic Spring Boot application with a CommandLineRunner. Note that the same problem also occurs when a Spring web service fails to start: the process does not exit because of the Hazelcast daemon threads.

Given that Spring Boot starts Hazelcast, it should stop it too.

invalid

Most helpful comment

I was mistaken earlier. Spring Framework will automatically infer a destroy method if a bean has a method named close or shutdown. HazelcastInstance has the latter and an application that uses our auto-configuration for Hazelcast shuts it down correctly.

The problem in this case is the custom cache configuration that you're using. You're creating a HazelcastInstance but not exposing it as a bean. Instead, you're wrapping it in a HazelcastCacheManager and exposing that as a bean. HazelcastCacheManger has no close or shutdown method so the underlying HazelcastInstance is left running when the context is closed.

You can fix the problem by exposing the HazelcastInstance that you're creating as a bean. Note that, as I described above, you also need to call close() on the application context:

diff --git a/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java b/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
index ad49bfd..5eaf9bd 100644
--- a/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
+++ b/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
@@ -22,7 +22,7 @@ public class TheApplication extends CachingConfigurerSupport
                {
                        SpringApplication app = new SpringApplication(TheApplication.class);
                        app.setWebEnvironment(false);
-                       app.run(args);
+                       app.run(args).close();
                }
                finally
                {
@@ -34,7 +34,11 @@ public class TheApplication extends CachingConfigurerSupport
        @Bean
        public CacheManager cacheManager()
        {
-               HazelcastInstance client = Hazelcast.newHazelcastInstance(new Config());
-               return new HazelcastCacheManager(client);
+               return new HazelcastCacheManager(hazelcastInstance());
+       }
+
+       @Bean
+       public HazelcastInstance hazelcastInstance() {
+               return Hazelcast.newHazelcastInstance(new Config());
        }
 }

All 4 comments

We're missing the configuration of a destroy method on the auto-configured HazelcastInstance. We need to call shutdown as part of the application context closing.

It's a shame that Hazelcast uses non-daemon threads. That means that you'll have to explicitly close the application context to get things to shut down as the non-daemon threads will prevent the JVM from exiting and, therefore, the shutdown hook that would normally close the context from running.

Thanks for the quick response!

I was mistaken earlier. Spring Framework will automatically infer a destroy method if a bean has a method named close or shutdown. HazelcastInstance has the latter and an application that uses our auto-configuration for Hazelcast shuts it down correctly.

The problem in this case is the custom cache configuration that you're using. You're creating a HazelcastInstance but not exposing it as a bean. Instead, you're wrapping it in a HazelcastCacheManager and exposing that as a bean. HazelcastCacheManger has no close or shutdown method so the underlying HazelcastInstance is left running when the context is closed.

You can fix the problem by exposing the HazelcastInstance that you're creating as a bean. Note that, as I described above, you also need to call close() on the application context:

diff --git a/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java b/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
index ad49bfd..5eaf9bd 100644
--- a/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
+++ b/src/main/java/nu/famroos/repro/hazelcast/shutdown/TheApplication.java
@@ -22,7 +22,7 @@ public class TheApplication extends CachingConfigurerSupport
                {
                        SpringApplication app = new SpringApplication(TheApplication.class);
                        app.setWebEnvironment(false);
-                       app.run(args);
+                       app.run(args).close();
                }
                finally
                {
@@ -34,7 +34,11 @@ public class TheApplication extends CachingConfigurerSupport
        @Bean
        public CacheManager cacheManager()
        {
-               HazelcastInstance client = Hazelcast.newHazelcastInstance(new Config());
-               return new HazelcastCacheManager(client);
+               return new HazelcastCacheManager(hazelcastInstance());
+       }
+
+       @Bean
+       public HazelcastInstance hazelcastInstance() {
+               return Hazelcast.newHazelcastInstance(new Config());
        }
 }

That fixes it indeed. Thank you!

Was this page helpful?
0 / 5 - 0 ratings