From 75e6b052024f26ee850588c9ed4ef98a3ee69cb1 Mon Sep 17 00:00:00 2001 From: ggivo Date: Wed, 18 Jun 2025 07:43:51 +0300 Subject: [PATCH 1/3] Add a test to verify failover on DNS unresolvable host error --- .../jedis/misc/AutomaticFailoverTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java index cd87689b6c..edb37a4850 100644 --- a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java +++ b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java @@ -1,5 +1,6 @@ package redis.clients.jedis.misc; +import java.net.UnknownHostException; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -18,8 +19,11 @@ import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; import redis.clients.jedis.util.IOUtils; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class AutomaticFailoverTest { @@ -87,6 +91,46 @@ public void transactionWithSwitch() { assertEquals("bar", jedis2.hget("thash", "foo")); } + @Test + public void commandFailoverUnresolvableHost() { + int slidingWindowMinCalls = 2; + int slidingWindowSize = 2; + + HostAndPort unresolvableHostAndPort = new HostAndPort("unresolvable", 6379); + MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( + getClusterConfigs(clientConfig, unresolvableHostAndPort, + workingEndpoint.getHostAndPort())).retryWaitDuration(1).retryMaxAttempts(1) + .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) + .circuitBreakerSlidingWindowSize(slidingWindowSize); + + RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); + MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + builder.build()); + cacheProvider.setClusterFailoverPostProcessor(failoverReporter); + + UnifiedJedis jedis = new UnifiedJedis(cacheProvider); + + String key = "hash-" + System.nanoTime(); + log.info("Starting calls to Redis"); + assertFalse(failoverReporter.failedOver); + + for (int attempt = 0; attempt < slidingWindowMinCalls; attempt++) { + Throwable thrown = assertThrows(JedisConnectionException.class, + () -> jedis.hset(key, "f1", "v1")); + assertThat(thrown.getCause(), instanceOf(UnknownHostException.class)); + assertFalse(failoverReporter.failedOver); + } + + // should failover now + jedis.hset(key, "f1", "v1"); + assertTrue(failoverReporter.failedOver); + + assertEquals(Collections.singletonMap("f1", "v1"), jedis.hgetAll(key)); + jedis.flushAll(); + + jedis.close(); + } + @Test public void commandFailover() { int slidingWindowMinCalls = 10; @@ -94,6 +138,7 @@ public void commandFailover() { MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())) + .retryWaitDuration(1) .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) .circuitBreakerSlidingWindowSize(slidingWindowSize); From 6c7bc28e61e570bc8dca4125564bd492172e7ca1 Mon Sep 17 00:00:00 2001 From: ggivo Date: Wed, 18 Jun 2025 08:18:09 +0300 Subject: [PATCH 2/3] formating --- .../jedis/misc/AutomaticFailoverTest.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java index edb37a4850..736500cf25 100644 --- a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java +++ b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java @@ -138,12 +138,12 @@ public void commandFailover() { MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())) - .retryWaitDuration(1) - .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) - .circuitBreakerSlidingWindowSize(slidingWindowSize); + .retryWaitDuration(1).circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) + .circuitBreakerSlidingWindowSize(slidingWindowSize); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider(builder.build()); + MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + builder.build()); cacheProvider.setClusterFailoverPostProcessor(failoverReporter); UnifiedJedis jedis = new UnifiedJedis(cacheProvider); @@ -177,12 +177,13 @@ public void pipelineFailover() { MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( getClusterConfigs(clientConfig, hostPortWithFailure, workingEndpoint.getHostAndPort())) - .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) - .circuitBreakerSlidingWindowSize(slidingWindowSize) - .fallbackExceptionList(Collections.singletonList(JedisConnectionException.class)); + .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) + .circuitBreakerSlidingWindowSize(slidingWindowSize) + .fallbackExceptionList(Collections.singletonList(JedisConnectionException.class)); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider(builder.build()); + MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + builder.build()); cacheProvider.setClusterFailoverPostProcessor(failoverReporter); UnifiedJedis jedis = new UnifiedJedis(cacheProvider); @@ -209,13 +210,15 @@ public void failoverFromAuthError() { int slidingWindowSize = 10; MultiClusterClientConfig.Builder builder = new MultiClusterClientConfig.Builder( - getClusterConfigs(clientConfig, endpointForAuthFailure.getHostAndPort(), workingEndpoint.getHostAndPort())) - .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) - .circuitBreakerSlidingWindowSize(slidingWindowSize) - .fallbackExceptionList(Collections.singletonList(JedisAccessControlException.class)); + getClusterConfigs(clientConfig, endpointForAuthFailure.getHostAndPort(), + workingEndpoint.getHostAndPort())) + .circuitBreakerSlidingWindowMinCalls(slidingWindowMinCalls) + .circuitBreakerSlidingWindowSize(slidingWindowSize) + .fallbackExceptionList(Collections.singletonList(JedisAccessControlException.class)); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider(builder.build()); + MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + builder.build()); cacheProvider.setClusterFailoverPostProcessor(failoverReporter); UnifiedJedis jedis = new UnifiedJedis(cacheProvider); From a4e0bf95df752cfcc84650ed73ec219b918ce3e6 Mon Sep 17 00:00:00 2001 From: ggivo Date: Wed, 18 Jun 2025 11:00:50 +0300 Subject: [PATCH 3/3] address review comments --- .../jedis/misc/AutomaticFailoverTest.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java index 736500cf25..d87b8a6bc1 100644 --- a/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java +++ b/src/test/java/redis/clients/jedis/misc/AutomaticFailoverTest.java @@ -104,11 +104,11 @@ public void commandFailoverUnresolvableHost() { .circuitBreakerSlidingWindowSize(slidingWindowSize); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + MultiClusterPooledConnectionProvider connectionProvider = new MultiClusterPooledConnectionProvider( builder.build()); - cacheProvider.setClusterFailoverPostProcessor(failoverReporter); + connectionProvider.setClusterFailoverPostProcessor(failoverReporter); - UnifiedJedis jedis = new UnifiedJedis(cacheProvider); + UnifiedJedis jedis = new UnifiedJedis(connectionProvider); String key = "hash-" + System.nanoTime(); log.info("Starting calls to Redis"); @@ -142,11 +142,11 @@ public void commandFailover() { .circuitBreakerSlidingWindowSize(slidingWindowSize); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + MultiClusterPooledConnectionProvider connectionProvider = new MultiClusterPooledConnectionProvider( builder.build()); - cacheProvider.setClusterFailoverPostProcessor(failoverReporter); + connectionProvider.setClusterFailoverPostProcessor(failoverReporter); - UnifiedJedis jedis = new UnifiedJedis(cacheProvider); + UnifiedJedis jedis = new UnifiedJedis(connectionProvider); String key = "hash-" + System.nanoTime(); log.info("Starting calls to Redis"); @@ -182,11 +182,11 @@ public void pipelineFailover() { .fallbackExceptionList(Collections.singletonList(JedisConnectionException.class)); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + MultiClusterPooledConnectionProvider connectionProvider = new MultiClusterPooledConnectionProvider( builder.build()); - cacheProvider.setClusterFailoverPostProcessor(failoverReporter); + connectionProvider.setClusterFailoverPostProcessor(failoverReporter); - UnifiedJedis jedis = new UnifiedJedis(cacheProvider); + UnifiedJedis jedis = new UnifiedJedis(connectionProvider); String key = "hash-" + System.nanoTime(); log.info("Starting calls to Redis"); @@ -217,11 +217,11 @@ public void failoverFromAuthError() { .fallbackExceptionList(Collections.singletonList(JedisAccessControlException.class)); RedisFailoverReporter failoverReporter = new RedisFailoverReporter(); - MultiClusterPooledConnectionProvider cacheProvider = new MultiClusterPooledConnectionProvider( + MultiClusterPooledConnectionProvider connectionProvider = new MultiClusterPooledConnectionProvider( builder.build()); - cacheProvider.setClusterFailoverPostProcessor(failoverReporter); + connectionProvider.setClusterFailoverPostProcessor(failoverReporter); - UnifiedJedis jedis = new UnifiedJedis(cacheProvider); + UnifiedJedis jedis = new UnifiedJedis(connectionProvider); String key = "hash-" + System.nanoTime(); log.info("Starting calls to Redis");