Skip to content

Commit 55e8a97

Browse files
committed
Merge pull request #17499 from nosan
* pr/17499: Polish "Add HealthIndicator for Hazelcast" Add HealthIndicator for Hazelcast Closes gh-17499
2 parents bc8514c + be988d7 commit 55e8a97

File tree

8 files changed

+340
-0
lines changed

8 files changed

+340
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.hazelcast;
18+
19+
import java.util.Map;
20+
21+
import com.hazelcast.core.HazelcastInstance;
22+
23+
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration;
24+
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
25+
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
26+
import org.springframework.boot.actuate.hazelcast.HazelcastHealthIndicator;
27+
import org.springframework.boot.actuate.health.HealthIndicator;
28+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
29+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
30+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
33+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
34+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
35+
import org.springframework.context.annotation.Bean;
36+
import org.springframework.context.annotation.Configuration;
37+
38+
/**
39+
* {@link EnableAutoConfiguration Auto-configuration} for
40+
* {@link HazelcastHealthIndicator}.
41+
*
42+
* @author Dmytro Nosan
43+
* @since 2.2.0
44+
*/
45+
@Configuration(proxyBeanMethods = false)
46+
@ConditionalOnClass(HazelcastInstance.class)
47+
@ConditionalOnBean(HazelcastInstance.class)
48+
@ConditionalOnEnabledHealthIndicator("hazelcast")
49+
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
50+
@AutoConfigureAfter(HazelcastAutoConfiguration.class)
51+
public class HazelcastHealthIndicatorAutoConfiguration
52+
extends CompositeHealthIndicatorConfiguration<HazelcastHealthIndicator, HazelcastInstance> {
53+
54+
@Bean
55+
@ConditionalOnMissingBean(name = "hazelcastHealthIndicator")
56+
public HealthIndicator hazelcastHealthIndicator(Map<String, HazelcastInstance> hazelcastInstances) {
57+
return createHealthIndicator(hazelcastInstances);
58+
}
59+
60+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for actuator Hazelcast concerns.
19+
*/
20+
package org.springframework.boot.actuate.autoconfigure.hazelcast;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.hazelcast;
18+
19+
import com.hazelcast.core.HazelcastInstance;
20+
import org.junit.jupiter.api.Test;
21+
22+
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
23+
import org.springframework.boot.actuate.hazelcast.HazelcastHealthIndicator;
24+
import org.springframework.boot.actuate.health.Health;
25+
import org.springframework.boot.actuate.health.Status;
26+
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
28+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Integration tests for {@link HazelcastHealthIndicatorAutoConfiguration}.
34+
*
35+
* @author Dmytro Nosan
36+
*/
37+
class HazelcastHealthIndicatorAutoConfigurationIntegrationTests {
38+
39+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
40+
.withConfiguration(AutoConfigurations.of(HazelcastHealthIndicatorAutoConfiguration.class,
41+
HazelcastAutoConfiguration.class, HealthIndicatorAutoConfiguration.class));
42+
43+
@Test
44+
void hazelcastUp() {
45+
this.contextRunner.run((context) -> {
46+
assertThat(context).hasSingleBean(HazelcastInstance.class).hasSingleBean(HazelcastHealthIndicator.class);
47+
HazelcastInstance hazelcast = context.getBean(HazelcastInstance.class);
48+
Health health = context.getBean(HazelcastHealthIndicator.class).health();
49+
assertThat(health.getStatus()).isEqualTo(Status.UP);
50+
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name", hazelcast.getName())
51+
.containsEntry("uuid", hazelcast.getLocalEndpoint().getUuid());
52+
});
53+
}
54+
55+
@Test
56+
void hazelcastDown() {
57+
this.contextRunner.run((context) -> {
58+
context.getBean(HazelcastInstance.class).shutdown();
59+
assertThat(context).hasSingleBean(HazelcastHealthIndicator.class);
60+
Health health = context.getBean(HazelcastHealthIndicator.class).health();
61+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
62+
});
63+
}
64+
65+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.hazelcast;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
22+
import org.springframework.boot.actuate.hazelcast.HazelcastHealthIndicator;
23+
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
24+
import org.springframework.boot.autoconfigure.AutoConfigurations;
25+
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
26+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
30+
/**
31+
* Tests for {@link HazelcastHealthIndicatorAutoConfiguration}.
32+
*
33+
* @author Dmytro Nosan
34+
*/
35+
class HazelcastHealthIndicatorAutoConfigurationTests {
36+
37+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
38+
.withConfiguration(AutoConfigurations.of(HazelcastAutoConfiguration.class,
39+
HazelcastHealthIndicatorAutoConfiguration.class, HealthIndicatorAutoConfiguration.class));
40+
41+
@Test
42+
void runShouldCreateIndicator() {
43+
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(HazelcastHealthIndicator.class)
44+
.doesNotHaveBean(ApplicationHealthIndicator.class));
45+
}
46+
47+
@Test
48+
void runWhenDisabledShouldNotCreateIndicator() {
49+
this.contextRunner.withPropertyValues("management.health.hazelcast.enabled:false")
50+
.run((context) -> assertThat(context).doesNotHaveBean(HazelcastHealthIndicator.class)
51+
.hasSingleBean(ApplicationHealthIndicator.class));
52+
}
53+
54+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.hazelcast;
18+
19+
import com.hazelcast.core.HazelcastInstance;
20+
21+
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
22+
import org.springframework.boot.actuate.health.Health;
23+
import org.springframework.boot.actuate.health.HealthIndicator;
24+
import org.springframework.util.Assert;
25+
26+
/**
27+
* {@link HealthIndicator} for Hazelcast.
28+
*
29+
* @author Dmytro Nosan
30+
* @author Stephane Nicoll
31+
* @since 2.2.0
32+
*/
33+
public class HazelcastHealthIndicator extends AbstractHealthIndicator {
34+
35+
private final HazelcastInstance hazelcast;
36+
37+
public HazelcastHealthIndicator(HazelcastInstance hazelcast) {
38+
super("Hazelcast health check failed");
39+
Assert.notNull(hazelcast, "HazelcastInstance must not be null");
40+
this.hazelcast = hazelcast;
41+
}
42+
43+
@Override
44+
protected void doHealthCheck(Health.Builder builder) {
45+
this.hazelcast.executeTransaction((context) -> {
46+
builder.up().withDetail("name", this.hazelcast.getName()).withDetail("uuid",
47+
this.hazelcast.getLocalEndpoint().getUuid());
48+
return null;
49+
});
50+
}
51+
52+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Actuator support for Hazelcast.
19+
*/
20+
package org.springframework.boot.actuate.hazelcast;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.hazelcast;
18+
19+
import com.hazelcast.core.Endpoint;
20+
import com.hazelcast.core.HazelcastException;
21+
import com.hazelcast.core.HazelcastInstance;
22+
import com.hazelcast.transaction.TransactionalTask;
23+
import org.junit.jupiter.api.Test;
24+
25+
import org.springframework.boot.actuate.health.Health;
26+
import org.springframework.boot.actuate.health.Status;
27+
28+
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.mockito.ArgumentMatchers.any;
30+
import static org.mockito.BDDMockito.when;
31+
import static org.mockito.Mockito.mock;
32+
33+
/**
34+
* Tests for {@link HazelcastHealthIndicator}.
35+
*
36+
* @author Dmytro Nosan
37+
* @author Stephane Nicoll
38+
*/
39+
class HazelcastHealthIndicatorTests {
40+
41+
private final HazelcastInstance hazelcast = mock(HazelcastInstance.class);
42+
43+
@Test
44+
void hazelcastUp() {
45+
Endpoint endpoint = mock(Endpoint.class);
46+
when(this.hazelcast.getName()).thenReturn("hz0-instance");
47+
when(this.hazelcast.getLocalEndpoint()).thenReturn(endpoint);
48+
when(endpoint.getUuid()).thenReturn("7581bb2f-879f-413f-b574-0071d7519eb0");
49+
when(this.hazelcast.executeTransaction(any())).thenAnswer((invocation) -> {
50+
TransactionalTask<?> task = invocation.getArgument(0);
51+
return task.execute(null);
52+
});
53+
Health health = new HazelcastHealthIndicator(this.hazelcast).health();
54+
assertThat(health.getStatus()).isEqualTo(Status.UP);
55+
assertThat(health.getDetails()).containsOnlyKeys("name", "uuid").containsEntry("name", "hz0-instance")
56+
.containsEntry("uuid", "7581bb2f-879f-413f-b574-0071d7519eb0");
57+
}
58+
59+
@Test
60+
void hazelcastDown() {
61+
when(this.hazelcast.executeTransaction(any())).thenThrow(new HazelcastException());
62+
Health health = new HazelcastHealthIndicator(this.hazelcast).health();
63+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
64+
}
65+
66+
}

spring-boot-project/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,9 @@ The following `HealthIndicators` are auto-configured by Spring Boot when appropr
764764
|{sc-spring-boot-actuator}/elasticsearch/ElasticsearchHealthIndicator.{sc-ext}[`ElasticsearchHealthIndicator`]
765765
|Checks that an Elasticsearch cluster is up.
766766

767+
|{sc-spring-boot-actuator}/hazelcast/HazelcastHealthIndicator.{sc-ext}[`HazelcastHealthIndicator`]
768+
|Checks that an Hazelcast server is up.
769+
767770
|{sc-spring-boot-actuator}/influx/InfluxDbHealthIndicator.{sc-ext}[`InfluxDbHealthIndicator`]
768771
|Checks that an InfluxDB server is up.
769772

0 commit comments

Comments
 (0)