Skip to content

Commit f31141d

Browse files
hoanvhwilkinsona
authored andcommitted
Mark Redis as down when cluster_state is fail
See gh-27300
1 parent 96e58d8 commit f31141d

File tree

5 files changed

+111
-36
lines changed

5 files changed

+111
-36
lines changed

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,16 @@ static Builder up(Health.Builder builder, Properties info) {
3838
return builder.up();
3939
}
4040

41-
static Builder up(Health.Builder builder, ClusterInfo clusterInfo) {
41+
static Builder info(Health.Builder builder, ClusterInfo clusterInfo) {
4242
builder.withDetail("cluster_size", clusterInfo.getClusterSize());
4343
builder.withDetail("slots_up", clusterInfo.getSlotsOk());
4444
builder.withDetail("slots_fail", clusterInfo.getSlotsFail());
45-
return builder.up();
45+
46+
if ("fail".equalsIgnoreCase(clusterInfo.getState())) {
47+
return builder.down();
48+
} else {
49+
return builder.up();
50+
}
4651
}
4752

4853
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ protected void doHealthCheck(Health.Builder builder) throws Exception {
5757

5858
private void doHealthCheck(Health.Builder builder, RedisConnection connection) {
5959
if (connection instanceof RedisClusterConnection) {
60-
RedisHealth.up(builder, ((RedisClusterConnection) connection).clusterGetClusterInfo());
60+
RedisHealth.info(builder, ((RedisClusterConnection) connection).clusterGetClusterInfo());
6161
}
6262
else {
6363
RedisHealth.up(builder, connection.info("server"));

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ private Mono<Health> doHealthCheck(Health.Builder builder, ReactiveRedisConnecti
6565
private Mono<Health> getHealth(Health.Builder builder, ReactiveRedisConnection connection) {
6666
if (connection instanceof ReactiveRedisClusterConnection) {
6767
return ((ReactiveRedisClusterConnection) connection).clusterGetClusterInfo()
68-
.map((info) -> up(builder, info));
68+
.map(info -> info(builder, info));
6969
}
7070
return connection.serverCommands().info("server").map((info) -> up(builder, info));
7171
}
@@ -74,8 +74,8 @@ private Health up(Health.Builder builder, Properties info) {
7474
return RedisHealth.up(builder, info).build();
7575
}
7676

77-
private Health up(Health.Builder builder, ClusterInfo clusterInfo) {
78-
return RedisHealth.up(builder, clusterInfo).build();
77+
private Health info(Health.Builder builder, ClusterInfo clusterInfo) {
78+
return RedisHealth.info(builder, clusterInfo).build();
7979
}
8080

8181
}

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

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,25 +75,58 @@ private RedisHealthIndicator createHealthIndicator(RedisConnection redisConnecti
7575
}
7676

7777
@Test
78-
void redisClusterIsUp() {
79-
Properties clusterProperties = new Properties();
78+
void redisClusterIsUpWithoutState() {
79+
final Properties clusterProperties = new Properties();
8080
clusterProperties.setProperty("cluster_size", "4");
8181
clusterProperties.setProperty("cluster_slots_ok", "4");
8282
clusterProperties.setProperty("cluster_slots_fail", "0");
83-
List<RedisClusterNode> redisMasterNodes = Arrays.asList(new RedisClusterNode("127.0.0.1", 7001),
84-
new RedisClusterNode("127.0.0.2", 7001));
85-
RedisClusterConnection redisConnection = mock(RedisClusterConnection.class);
86-
given(redisConnection.clusterGetNodes()).willReturn(redisMasterNodes);
87-
given(redisConnection.clusterGetClusterInfo()).willReturn(new ClusterInfo(clusterProperties));
88-
RedisConnectionFactory redisConnectionFactory = mock(RedisConnectionFactory.class);
89-
given(redisConnectionFactory.getConnection()).willReturn(redisConnection);
90-
RedisHealthIndicator healthIndicator = new RedisHealthIndicator(redisConnectionFactory);
91-
Health health = healthIndicator.health();
83+
final RedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
84+
85+
final RedisHealthIndicator healthIndicator = new RedisHealthIndicator(redisConnectionFactory);
86+
final Health health = healthIndicator.health();
9287
assertThat(health.getStatus()).isEqualTo(Status.UP);
9388
assertThat(health.getDetails().get("cluster_size")).isEqualTo(4L);
9489
assertThat(health.getDetails().get("slots_up")).isEqualTo(4L);
9590
assertThat(health.getDetails().get("slots_fail")).isEqualTo(0L);
9691
verify(redisConnectionFactory, atLeastOnce()).getConnection();
9792
}
9893

94+
@Test
95+
void redisClusterIsUpWithState() {
96+
final Properties clusterProperties = new Properties();
97+
clusterProperties.setProperty("cluster_state", "ok");
98+
clusterProperties.setProperty("cluster_size", "4");
99+
clusterProperties.setProperty("cluster_slots_ok", "4");
100+
clusterProperties.setProperty("cluster_slots_fail", "0");
101+
final RedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
102+
103+
final RedisHealthIndicator healthIndicator = new RedisHealthIndicator(redisConnectionFactory);
104+
final Health health = healthIndicator.health();
105+
assertThat(health.getStatus()).isEqualTo(Status.UP);
106+
}
107+
108+
@Test
109+
void redisClusterIsDown() {
110+
final Properties clusterProperties = new Properties();
111+
clusterProperties.setProperty("cluster_state", "fail");
112+
clusterProperties.setProperty("cluster_size", "3");
113+
clusterProperties.setProperty("cluster_slots_ok", "4");
114+
clusterProperties.setProperty("cluster_slots_fail", "0");
115+
final RedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
116+
117+
final RedisHealthIndicator healthIndicator = new RedisHealthIndicator(redisConnectionFactory);
118+
final Health health = healthIndicator.health();
119+
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
120+
}
121+
122+
private static RedisConnectionFactory mockRedisClusterConnectionFactory(Properties clusterProperties) {
123+
final List<RedisClusterNode> redisMasterNodes = Arrays.asList(new RedisClusterNode("127.0.0.1", 7001),
124+
new RedisClusterNode("127.0.0.2", 7001));
125+
final RedisClusterConnection redisConnection = mock(RedisClusterConnection.class);
126+
given(redisConnection.clusterGetNodes()).willReturn(redisMasterNodes);
127+
given(redisConnection.clusterGetClusterInfo()).willReturn(new ClusterInfo(clusterProperties));
128+
final RedisConnectionFactory redisConnectionFactory = mock(RedisConnectionFactory.class);
129+
given(redisConnectionFactory.getConnection()).willReturn(redisConnection);
130+
return redisConnectionFactory;
131+
}
99132
}

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

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616

1717
package org.springframework.boot.actuate.redis;
1818

19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.BDDMockito.given;
21+
import static org.mockito.Mockito.mock;
22+
import static org.mockito.Mockito.verify;
23+
1924
import java.util.Properties;
2025

21-
import io.lettuce.core.RedisConnectionException;
2226
import org.junit.jupiter.api.Test;
23-
import reactor.core.publisher.Mono;
24-
import reactor.test.StepVerifier;
25-
2627
import org.springframework.boot.actuate.health.Health;
2728
import org.springframework.boot.actuate.health.Status;
2829
import org.springframework.data.redis.RedisConnectionFailureException;
@@ -32,10 +33,9 @@
3233
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
3334
import org.springframework.data.redis.connection.ReactiveServerCommands;
3435

35-
import static org.assertj.core.api.Assertions.assertThat;
36-
import static org.mockito.BDDMockito.given;
37-
import static org.mockito.Mockito.mock;
38-
import static org.mockito.Mockito.verify;
36+
import io.lettuce.core.RedisConnectionException;
37+
import reactor.core.publisher.Mono;
38+
import reactor.test.StepVerifier;
3939

4040
/**
4141
* Tests for {@link RedisReactiveHealthIndicator}.
@@ -67,25 +67,54 @@ void redisIsUp() {
6767
}
6868

6969
@Test
70-
void redisClusterIsUp() {
71-
Properties clusterProperties = new Properties();
70+
void redisClusterIsUpWithoutState() {
71+
final Properties clusterProperties = new Properties();
7272
clusterProperties.setProperty("cluster_size", "4");
7373
clusterProperties.setProperty("cluster_slots_ok", "4");
7474
clusterProperties.setProperty("cluster_slots_fail", "0");
75-
ReactiveRedisClusterConnection redisConnection = mock(ReactiveRedisClusterConnection.class);
76-
given(redisConnection.closeLater()).willReturn(Mono.empty());
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);
81-
Mono<Health> health = healthIndicator.health();
82-
StepVerifier.create(health).consumeNextWith((h) -> {
75+
final ReactiveRedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
76+
77+
final RedisReactiveHealthIndicator healthIndicator = new RedisReactiveHealthIndicator(redisConnectionFactory);
78+
final Mono<Health> health = healthIndicator.health();
79+
StepVerifier.create(health).consumeNextWith(h -> {
8380
assertThat(h.getStatus()).isEqualTo(Status.UP);
8481
assertThat(h.getDetails().get("cluster_size")).isEqualTo(4L);
8582
assertThat(h.getDetails().get("slots_up")).isEqualTo(4L);
8683
assertThat(h.getDetails().get("slots_fail")).isEqualTo(0L);
8784
}).verifyComplete();
88-
verify(redisConnection).closeLater();
85+
verify(redisConnectionFactory.getReactiveConnection()).closeLater();
86+
}
87+
88+
@Test
89+
void redisClusterIsUpWithState() {
90+
final Properties clusterProperties = new Properties();
91+
clusterProperties.setProperty("cluster_state", "ok");
92+
clusterProperties.setProperty("cluster_size", "4");
93+
clusterProperties.setProperty("cluster_slots_ok", "4");
94+
clusterProperties.setProperty("cluster_slots_fail", "0");
95+
final ReactiveRedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
96+
97+
final RedisReactiveHealthIndicator healthIndicator = new RedisReactiveHealthIndicator(redisConnectionFactory);
98+
final Mono<Health> health = healthIndicator.health();
99+
StepVerifier.create(health).consumeNextWith(h -> {
100+
assertThat(h.getStatus()).isEqualTo(Status.UP);
101+
}).verifyComplete();
102+
}
103+
104+
@Test
105+
void redisClusterIsDown() {
106+
final Properties clusterProperties = new Properties();
107+
clusterProperties.setProperty("cluster_state", "fail");
108+
clusterProperties.setProperty("cluster_size", "3");
109+
clusterProperties.setProperty("cluster_slots_ok", "4");
110+
clusterProperties.setProperty("cluster_slots_fail", "0");
111+
final ReactiveRedisConnectionFactory redisConnectionFactory = mockRedisClusterConnectionFactory(clusterProperties);
112+
113+
final RedisReactiveHealthIndicator healthIndicator = new RedisReactiveHealthIndicator(redisConnectionFactory);
114+
final Mono<Health> health = healthIndicator.health();
115+
StepVerifier.create(health).consumeNextWith(h -> {
116+
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
117+
}).verifyComplete();
89118
}
90119

91120
@Test
@@ -121,4 +150,12 @@ private RedisReactiveHealthIndicator createHealthIndicator(ReactiveRedisConnecti
121150
return new RedisReactiveHealthIndicator(redisConnectionFactory);
122151
}
123152

153+
private static ReactiveRedisConnectionFactory mockRedisClusterConnectionFactory(Properties clusterProperties) {
154+
final ReactiveRedisClusterConnection redisConnection = mock(ReactiveRedisClusterConnection.class);
155+
given(redisConnection.closeLater()).willReturn(Mono.empty());
156+
given(redisConnection.clusterGetClusterInfo()).willReturn(Mono.just(new ClusterInfo(clusterProperties)));
157+
final ReactiveRedisConnectionFactory redisConnectionFactory = mock(ReactiveRedisConnectionFactory.class);
158+
given(redisConnectionFactory.getReactiveConnection()).willReturn(redisConnection);
159+
return redisConnectionFactory;
160+
}
124161
}

0 commit comments

Comments
 (0)