Skip to content

Commit 2496202

Browse files
tommyk-gearssnicoll
authored andcommitted
Improve Hazelcast health indicator to check that Hazelcast is running
This commit improves the Hazelcast health indicator to fail if the Lifecycle manager indicates that the instance is no longer running. This is needed because when the default Out-Of-Memory handler in Hazelcast detects a OOM error, and terminates Hazelcast, it does so on the node but not via the Hazelcast lifecycle manager - and the results is that it is still possible to successfully execute transactions in Hazelcast after this termination. The health indicator should not report UP after Hazelcast has detected an OOM and terminated itself. See gh-46877 Signed-off-by: Tommy Karlsson <[email protected]>
1 parent aa46a66 commit 2496202

File tree

2 files changed

+49
-15
lines changed

2 files changed

+49
-15
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/hazelcast/HazelcastHealthIndicator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
*
2929
* @author Dmytro Nosan
3030
* @author Stephane Nicoll
31+
* @author Tommy Karlsson
3132
* @since 2.2.0
3233
*/
3334
public class HazelcastHealthIndicator extends AbstractHealthIndicator {
@@ -42,6 +43,10 @@ public HazelcastHealthIndicator(HazelcastInstance hazelcast) {
4243

4344
@Override
4445
protected void doHealthCheck(Health.Builder builder) {
46+
if (!this.hazelcast.getLifecycleService().isRunning()) {
47+
builder.down();
48+
return;
49+
}
4550
this.hazelcast.executeTransaction((context) -> {
4651
String uuid = this.hazelcast.getLocalEndpoint().getUuid().toString();
4752
builder.up().withDetail("name", this.hazelcast.getName()).withDetail("uuid", uuid);

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/hazelcast/HazelcastHealthIndicatorTests.java

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import com.hazelcast.core.HazelcastException;
2020
import com.hazelcast.core.HazelcastInstance;
21+
import com.hazelcast.instance.impl.HazelcastInstanceProxy;
22+
import com.hazelcast.instance.impl.OutOfMemoryHandlerHelper;
2123
import org.junit.jupiter.api.Test;
2224

2325
import org.springframework.boot.actuate.health.Health;
@@ -37,25 +39,26 @@
3739
*
3840
* @author Dmytro Nosan
3941
* @author Stephane Nicoll
42+
* @author Tommy Karlsson
4043
*/
44+
@WithResource(name = "hazelcast.xml", content = """
45+
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
46+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
47+
xsi:schemaLocation="http://www.hazelcast.com/schema/config
48+
http://www.hazelcast.com/schema/config/hazelcast-config-5.0.xsd">
49+
<instance-name>actuator-hazelcast</instance-name>
50+
<map name="defaultCache" />
51+
<network>
52+
<join>
53+
<auto-detection enabled="false"/>
54+
<multicast enabled="false"/>
55+
</join>
56+
</network>
57+
</hazelcast>
58+
""")
4159
class HazelcastHealthIndicatorTests {
4260

4361
@Test
44-
@WithResource(name = "hazelcast.xml", content = """
45-
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
46-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
47-
xsi:schemaLocation="http://www.hazelcast.com/schema/config
48-
http://www.hazelcast.com/schema/config/hazelcast-config-5.0.xsd">
49-
<instance-name>actuator-hazelcast</instance-name>
50-
<map name="defaultCache" />
51-
<network>
52-
<join>
53-
<auto-detection enabled="false"/>
54-
<multicast enabled="false"/>
55-
</join>
56-
</network>
57-
</hazelcast>
58-
""")
5962
void hazelcastUp() {
6063
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
6164
.withPropertyValues("spring.hazelcast.config=hazelcast.xml")
@@ -69,6 +72,32 @@ void hazelcastUp() {
6972
});
7073
}
7174

75+
@Test
76+
void hazelcastShutdown() {
77+
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
78+
.withPropertyValues("spring.hazelcast.config=hazelcast.xml")
79+
.run((context) -> {
80+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
81+
hazelcast.shutdown();
82+
Health health = new HazelcastHealthIndicator(hazelcast).health();
83+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
84+
});
85+
}
86+
87+
@Test
88+
void hazelcastOOMShutdown() {
89+
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
90+
.withPropertyValues("spring.hazelcast.config=hazelcast.xml")
91+
.run((context) -> {
92+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
93+
HazelcastInstance original = ((HazelcastInstanceProxy) hazelcast).getOriginal();
94+
OutOfMemoryHandlerHelper.tryCloseConnections(original);
95+
OutOfMemoryHandlerHelper.tryShutdown(original);
96+
Health health = new HazelcastHealthIndicator(hazelcast).health();
97+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
98+
});
99+
}
100+
72101
@Test
73102
void hazelcastDown() {
74103
HazelcastInstance hazelcast = mock(HazelcastInstance.class);

0 commit comments

Comments
 (0)