Merge pull request #46877 from tommyk-gears

* pr/46877:
  Polish contribution
  Improve Hazelcast health indicator to check that Hazelcast is running

Closes gh-46877
This commit is contained in:
Stéphane Nicoll 2025-08-19 16:35:15 +02:00
commit e1db00b411
2 changed files with 56 additions and 16 deletions

View File

@ -28,6 +28,7 @@ import org.springframework.util.Assert;
* *
* @author Dmytro Nosan * @author Dmytro Nosan
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Tommy Karlsson
* @since 2.2.0 * @since 2.2.0
*/ */
public class HazelcastHealthIndicator extends AbstractHealthIndicator { public class HazelcastHealthIndicator extends AbstractHealthIndicator {
@ -42,6 +43,10 @@ public class HazelcastHealthIndicator extends AbstractHealthIndicator {
@Override @Override
protected void doHealthCheck(Health.Builder builder) { protected void doHealthCheck(Health.Builder builder) {
if (!this.hazelcast.getLifecycleService().isRunning()) {
builder.down();
return;
}
this.hazelcast.executeTransaction((context) -> { this.hazelcast.executeTransaction((context) -> {
String uuid = this.hazelcast.getLocalEndpoint().getUuid().toString(); String uuid = this.hazelcast.getLocalEndpoint().getUuid().toString();
builder.up().withDetail("name", this.hazelcast.getName()).withDetail("uuid", uuid); builder.up().withDetail("name", this.hazelcast.getName()).withDetail("uuid", uuid);

View File

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.hazelcast;
import com.hazelcast.core.HazelcastException; import com.hazelcast.core.HazelcastException;
import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.LifecycleService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.health.Health; import org.springframework.boot.actuate.health.Health;
@ -30,6 +31,7 @@ import org.springframework.boot.testsupport.classpath.resources.WithResource;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
@ -37,11 +39,9 @@ import static org.mockito.Mockito.mock;
* *
* @author Dmytro Nosan * @author Dmytro Nosan
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Tommy Karlsson
*/ */
class HazelcastHealthIndicatorTests { @WithResource(name = "hazelcast.xml", content = """
@Test
@WithResource(name = "hazelcast.xml", content = """
<hazelcast xmlns="http://www.hazelcast.com/schema/config" <hazelcast xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/config xsi:schemaLocation="http://www.hazelcast.com/schema/config
@ -56,6 +56,9 @@ class HazelcastHealthIndicatorTests {
</network> </network>
</hazelcast> </hazelcast>
""") """)
class HazelcastHealthIndicatorTests {
@Test
void hazelcastUp() { void hazelcastUp() {
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class)) new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
.withPropertyValues("spring.hazelcast.config=hazelcast.xml") .withPropertyValues("spring.hazelcast.config=hazelcast.xml")
@ -69,12 +72,44 @@ class HazelcastHealthIndicatorTests {
}); });
} }
@Test
void hazelcastShutdown() {
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class))
.withPropertyValues("spring.hazelcast.config=hazelcast.xml")
.run((context) -> {
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
hazelcast.shutdown();
Health health = new HazelcastHealthIndicator(hazelcast).health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
});
}
@Test
void hazelcastLifecycleNotRunning() {
HazelcastInstance hazelcast = mockHazelcastInstance(false);
Health health = new HazelcastHealthIndicator(hazelcast).health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
then(hazelcast).should().getLifecycleService();
then(hazelcast).shouldHaveNoMoreInteractions();
}
@Test @Test
void hazelcastDown() { void hazelcastDown() {
HazelcastInstance hazelcast = mock(HazelcastInstance.class); HazelcastInstance hazelcast = mockHazelcastInstance(true);
given(hazelcast.executeTransaction(any())).willThrow(new HazelcastException()); given(hazelcast.executeTransaction(any())).willThrow(new HazelcastException());
Health health = new HazelcastHealthIndicator(hazelcast).health(); Health health = new HazelcastHealthIndicator(hazelcast).health();
assertThat(health.getStatus()).isEqualTo(Status.DOWN); assertThat(health.getStatus()).isEqualTo(Status.DOWN);
then(hazelcast).should().getLifecycleService();
then(hazelcast).should().executeTransaction(any());
then(hazelcast).shouldHaveNoMoreInteractions();
}
private static HazelcastInstance mockHazelcastInstance(boolean isRunning) {
LifecycleService lifecycleService = mock(LifecycleService.class);
given(lifecycleService.isRunning()).willReturn(isRunning);
HazelcastInstance hazelcastInstance = mock(HazelcastInstance.class);
given(hazelcastInstance.getLifecycleService()).willReturn(lifecycleService);
return hazelcastInstance;
} }
} }