Skip to content

Commit 3b58744

Browse files
Provide cluster info in RedisReactiveHealthIndicator
This commit changes the information provided by RedisReactiveHealthIndicator to include cluster details when Spring Data Redis detects that Redis is running in a clustered configuration. This brings the reactive and non-reactive Redis health indicators into alignment. Fixes gh-21514
1 parent dba8ca2 commit 3b58744

File tree

3 files changed

+42
-29
lines changed

3 files changed

+42
-29
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/redis/RedisHealthIndicator.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,19 @@
3434
*
3535
* @author Christian Dupuis
3636
* @author Richard Santana
37+
* @author Scott Frederick
3738
* @since 2.0.0
3839
*/
3940
public class RedisHealthIndicator extends AbstractHealthIndicator {
4041

4142
static final String VERSION = "version";
4243

44+
static final String CLUSTER_SIZE = "cluster_size";
45+
46+
static final String SLOTS_UP = "slots_up";
47+
48+
static final String SLOTS_FAIL = "slots_fail";
49+
4350
static final String REDIS_VERSION = "redis_version";
4451

4552
private final RedisConnectionFactory redisConnectionFactory;
@@ -56,9 +63,9 @@ protected void doHealthCheck(Health.Builder builder) throws Exception {
5663
try {
5764
if (connection instanceof RedisClusterConnection) {
5865
ClusterInfo clusterInfo = ((RedisClusterConnection) connection).clusterGetClusterInfo();
59-
builder.up().withDetail("cluster_size", clusterInfo.getClusterSize())
60-
.withDetail("slots_up", clusterInfo.getSlotsOk())
61-
.withDetail("slots_fail", clusterInfo.getSlotsFail());
66+
builder.up().withDetail(CLUSTER_SIZE, clusterInfo.getClusterSize())
67+
.withDetail(SLOTS_UP, clusterInfo.getSlotsOk())
68+
.withDetail(SLOTS_FAIL, clusterInfo.getSlotsFail());
6269
}
6370
else {
6471
Properties info = connection.info();

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/redis/RedisReactiveHealthIndicator.java

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
2525
import org.springframework.boot.actuate.health.Health;
2626
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
27+
import org.springframework.data.redis.connection.ClusterInfo;
2728
import org.springframework.data.redis.connection.ReactiveRedisClusterConnection;
2829
import org.springframework.data.redis.connection.ReactiveRedisConnection;
2930
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
@@ -52,32 +53,33 @@ protected Mono<Health> doHealthCheck(Health.Builder builder) {
5253
}
5354

5455
private Mono<Health> doHealthCheck(Health.Builder builder, ReactiveRedisConnection connection) {
55-
return connection.serverCommands().info()
56-
.map((info) -> up(builder, info, (connection instanceof ReactiveRedisClusterConnection)))
57-
.onErrorResume((ex) -> Mono.just(down(builder, ex)))
58-
.flatMap((health) -> connection.closeLater().thenReturn(health));
56+
if (connection instanceof ReactiveRedisClusterConnection) {
57+
ReactiveRedisClusterConnection clusterConnection = (ReactiveRedisClusterConnection) connection;
58+
return clusterConnection.clusterGetClusterInfo().map((info) -> up(builder, info))
59+
.onErrorResume((ex) -> Mono.just(down(builder, ex)))
60+
.flatMap((health) -> clusterConnection.closeLater().thenReturn(health));
61+
}
62+
else {
63+
return connection.serverCommands().info().map((info) -> up(builder, info))
64+
.onErrorResume((ex) -> Mono.just(down(builder, ex)))
65+
.flatMap((health) -> connection.closeLater().thenReturn(health));
66+
}
5967
}
6068

6169
private Mono<ReactiveRedisConnection> getConnection() {
6270
return Mono.fromSupplier(this.connectionFactory::getReactiveConnection)
6371
.subscribeOn(Schedulers.boundedElastic());
6472
}
6573

66-
private Health up(Health.Builder builder, Properties info, boolean isClusterConnection) {
67-
if (isClusterConnection) {
68-
return builder.up().withDetail(RedisHealthIndicator.VERSION, getClusterVersionProperty(info)).build();
69-
}
70-
else {
71-
return builder.up()
72-
.withDetail(RedisHealthIndicator.VERSION, info.getProperty(RedisHealthIndicator.REDIS_VERSION))
73-
.build();
74-
}
74+
private Health up(Health.Builder builder, Properties info) {
75+
return builder.up()
76+
.withDetail(RedisHealthIndicator.VERSION, info.getProperty(RedisHealthIndicator.REDIS_VERSION)).build();
7577
}
7678

77-
private Object getClusterVersionProperty(Properties info) {
78-
return info.keySet().stream().map(String.class::cast)
79-
.filter((key) -> key.endsWith(RedisHealthIndicator.REDIS_VERSION)).findFirst().map(info::get)
80-
.orElse("");
79+
private Health up(Health.Builder builder, ClusterInfo clusterInfo) {
80+
return builder.up().withDetail(RedisHealthIndicator.CLUSTER_SIZE, clusterInfo.getClusterSize())
81+
.withDetail(RedisHealthIndicator.SLOTS_UP, clusterInfo.getSlotsOk())
82+
.withDetail(RedisHealthIndicator.SLOTS_FAIL, clusterInfo.getSlotsFail()).build();
8183
}
8284

8385
private Health down(Health.Builder builder, Throwable cause) {

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/redis/RedisReactiveHealthIndicatorTests.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
import org.springframework.boot.actuate.health.Health;
2727
import org.springframework.boot.actuate.health.Status;
2828
import org.springframework.data.redis.RedisConnectionFailureException;
29-
import org.springframework.data.redis.connection.ReactiveClusterServerCommands;
29+
import org.springframework.data.redis.connection.ClusterInfo;
3030
import org.springframework.data.redis.connection.ReactiveRedisClusterConnection;
3131
import org.springframework.data.redis.connection.ReactiveRedisConnection;
3232
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
@@ -68,18 +68,22 @@ void redisIsUp() {
6868

6969
@Test
7070
void redisClusterIsUp() {
71-
Properties info = new Properties();
72-
info.put("127.0.0.1:7002.redis_version", "2.8.9");
73-
ReactiveRedisConnection redisConnection = mock(ReactiveRedisClusterConnection.class);
71+
Properties clusterProperties = new Properties();
72+
clusterProperties.setProperty("cluster_size", "4");
73+
clusterProperties.setProperty("cluster_slots_ok", "4");
74+
clusterProperties.setProperty("cluster_slots_fail", "0");
75+
ReactiveRedisClusterConnection redisConnection = mock(ReactiveRedisClusterConnection.class);
7476
given(redisConnection.closeLater()).willReturn(Mono.empty());
75-
ReactiveClusterServerCommands commands = mock(ReactiveClusterServerCommands.class);
76-
given(commands.info()).willReturn(Mono.just(info));
77-
RedisReactiveHealthIndicator healthIndicator = createHealthIndicator(redisConnection, commands);
77+
given(redisConnection.clusterGetClusterInfo()).willReturn(Mono.just(new ClusterInfo(clusterProperties)));
78+
ReactiveRedisConnectionFactory redisConnectionFactory = mock(ReactiveRedisConnectionFactory.class);
79+
given(redisConnectionFactory.getReactiveConnection()).willReturn(redisConnection);
80+
RedisReactiveHealthIndicator healthIndicator = new RedisReactiveHealthIndicator(redisConnectionFactory);
7881
Mono<Health> health = healthIndicator.health();
7982
StepVerifier.create(health).consumeNextWith((h) -> {
8083
assertThat(h.getStatus()).isEqualTo(Status.UP);
81-
assertThat(h.getDetails()).containsOnlyKeys("version");
82-
assertThat(h.getDetails().get("version")).isEqualTo("2.8.9");
84+
assertThat(h.getDetails().get("cluster_size")).isEqualTo(4L);
85+
assertThat(h.getDetails().get("slots_up")).isEqualTo(4L);
86+
assertThat(h.getDetails().get("slots_fail")).isEqualTo(0L);
8387
}).verifyComplete();
8488
verify(redisConnection).closeLater();
8589
}

0 commit comments

Comments
 (0)