From 069ea6ffe0d50473f9f25d98378cd3632f8864ac Mon Sep 17 00:00:00 2001 From: JuneYub Date: Sun, 10 Aug 2025 04:51:34 +0900 Subject: [PATCH 1/6] docs: Improve Javadoc for HostAndPortMapper (#4112) --- .../java/redis/clients/jedis/HostAndPortMapper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/redis/clients/jedis/HostAndPortMapper.java b/src/main/java/redis/clients/jedis/HostAndPortMapper.java index 68727d9ca6..a22c6c04f3 100644 --- a/src/main/java/redis/clients/jedis/HostAndPortMapper.java +++ b/src/main/java/redis/clients/jedis/HostAndPortMapper.java @@ -1,6 +1,17 @@ package redis.clients.jedis; +/** + * An interface for mapping Redis node addresses. + *

+ * It is used to translate an advertised server address to one that is reachable by the client, + * especially in network topologies involving NAT or containerization. + */ +@FunctionalInterface public interface HostAndPortMapper { + /** + * @param hap The original address from the server. + * @return The translated, reachable address. + */ HostAndPort getHostAndPort(HostAndPort hap); } From b35a51004ea3216d20ca2c864aed857b60eb346f Mon Sep 17 00:00:00 2001 From: JuneYub Date: Tue, 12 Aug 2025 23:45:43 +0900 Subject: [PATCH 2/6] docs: Improve Javadoc for HostAndPortMapper (#4112) --- docs/advanced-usage.md | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 0aad0e448f..1a3bd903af 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -211,6 +211,69 @@ To use Microsoft EntraID with AMR or ACR, for sure you will need to set up and c [Use Microsoft Entra](https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad?tabs=workforce-configuration) +## HostAndPortMapper + +When running Jedis in certain network environments, such as behind a NAT gateway, or within container orchestration systems like Docker or Kubernetes, the host and port that the client needs to connect to might be different from the host and port that the Redis Cluster nodes report. To handle this discrepancy, Jedis provides the `HostAndPortMapper` interface. + +This allows you to dynamically map the address reported by a Redis node to a different address that the client can actually reach. You can implement this either by creating a dedicated class or by using a concise lambda expression. + +### Implementing with a Dedicated Class + +You can provide your mapping logic by creating a class that implements the `HostAndPortMapper` interface. This approach is useful for more complex mapping logic or for reusability. + +First, define your custom mapper class: + +```java +public class DockerNATMapper implements HostAndPortMapper { + + // Key: The address reported by Redis (internal). + // Value: The address the client should connect to (external). + private final Map mapping; + + public DockerNATMapper(Map mapping) { + this.mapping = mapping; + } + + @Override + public HostAndPort get(HostAndPort hostAndPort) { + return mapping.getOrDefault(hostAndPort, hostAndPort); + } +} +``` + +Then, instantiate this class and pass it to the JedisCluster constructor: + +```java +Map nodeMapping = new HashMap<>(); +nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("localhost", 7001)); +nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("localhost", 7002)); + +Set initialNodes = new HashSet<>(); +initialNodes.add(new HostAndPort("localhost", 7001)); + +HostAndPortMapper mapper = new DockerNATMapper(nodeMapping); + +JedisCluster jedisCluster = new JedisCluster(initialNodes, "myuser", "mypassword", mapper); +``` + +Now, when JedisCluster discovers a node at "172.18.0.2:6379", the mapper will translate it to "localhost:7001" before attempting to connect. + +### Implementing with a Lambda Expression +Since HostAndPortMapper is a functional interface (it has only one abstract method), you can also provide the implementation more concisely using a lambda expression. This is often preferred for simpler, inline mapping logic. + +```java +Map nodeMapping = new HashMap<>(); +nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("localhost", 7001)); +nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("localhost", 7002)); + +Set initialNodes = new HashSet<>(); +initialNodes.add(new HostAndPort("localhost", 7001)); + +HostAndPortMapper mapper = internalAddress -> nodeMapping.getOrDefault(internalAddress, internalAddress); + +JedisCluster jedisCluster = new JedisCluster(initialNodes, "myuser", "mypassword", mapper); +``` + ## Miscellaneous ### A note about String and Binary - what is native? From 0f58ec6d0cd68e9ae1f01832238df641534ac90a Mon Sep 17 00:00:00 2001 From: JuneYub Date: Wed, 13 Aug 2025 23:35:50 +0900 Subject: [PATCH 3/6] docs: update HostAndPortMapper usage to use DefaultJedisClientConfig (#4112) --- docs/advanced-usage.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 1a3bd903af..01310a8622 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -253,7 +253,13 @@ initialNodes.add(new HostAndPort("localhost", 7001)); HostAndPortMapper mapper = new DockerNATMapper(nodeMapping); -JedisCluster jedisCluster = new JedisCluster(initialNodes, "myuser", "mypassword", mapper); +JedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder() + .user("myuser") + .password("mypassword") + .hostAndPortMapper(mapper) + .build(); + +JedisCluster jedisCluster = new JedisCluster(initialNodes, jedisClientConfig); ``` Now, when JedisCluster discovers a node at "172.18.0.2:6379", the mapper will translate it to "localhost:7001" before attempting to connect. @@ -271,7 +277,13 @@ initialNodes.add(new HostAndPort("localhost", 7001)); HostAndPortMapper mapper = internalAddress -> nodeMapping.getOrDefault(internalAddress, internalAddress); -JedisCluster jedisCluster = new JedisCluster(initialNodes, "myuser", "mypassword", mapper); +JedisClientConfig jedisClientConfig = DefaultJedisClientConfig.builder() + .user("myuser") + .password("mypassword") + .hostAndPortMapper(mapper) + .build(); + +JedisCluster jedisCluster = new JedisCluster(initialNodes, jedisClientConfig); ``` ## Miscellaneous From 75c16af74c2f3f14efe666b4ba529f6fcc7d9c90 Mon Sep 17 00:00:00 2001 From: JuneYub <91084695+JuneYub@users.noreply.github.com> Date: Thu, 14 Aug 2025 14:13:11 +0900 Subject: [PATCH 4/6] docs: update HostAndMapper advanced-usage.md --- docs/advanced-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index 01310a8622..e76172b557 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -235,7 +235,7 @@ public class DockerNATMapper implements HostAndPortMapper { } @Override - public HostAndPort get(HostAndPort hostAndPort) { + public HostAndPort getHostAndPort(HostAndPort hostAndPort) { return mapping.getOrDefault(hostAndPort, hostAndPort); } } From 049d6dfc712fce4a7cacf9af6154497e273b39ba Mon Sep 17 00:00:00 2001 From: ggivo Date: Thu, 14 Aug 2025 08:40:58 +0300 Subject: [PATCH 5/6] docs: add example use case --- docs/advanced-usage.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index e76172b557..0f7c2bbbe1 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -217,6 +217,20 @@ When running Jedis in certain network environments, such as behind a NAT gateway This allows you to dynamically map the address reported by a Redis node to a different address that the client can actually reach. You can implement this either by creating a dedicated class or by using a concise lambda expression. +### Example use case: NAT or Docker with different advertised ports +Suppose you run a Redis cluster inside Docker on a remote host. +Inside the cluster config, nodes announce addresses like: +``` +172.18.0.2:6379 +172.18.0.3:6379 +172.18.0.4:6379 +``` +But externally, you reach them through the host IP with mapped ports: +``` +my-redis.example.com:7001 +my-redis.example.com:7002 +my-redis.example.com:7003 +``` ### Implementing with a Dedicated Class You can provide your mapping logic by creating a class that implements the `HostAndPortMapper` interface. This approach is useful for more complex mapping logic or for reusability. @@ -245,11 +259,13 @@ Then, instantiate this class and pass it to the JedisCluster constructor: ```java Map nodeMapping = new HashMap<>(); -nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("localhost", 7001)); -nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("localhost", 7002)); +nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("my-redis.example.com", 7001)); +nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("my-redis.example.com", 7002)); +nodeMapping.put(new HostAndPort("172.18.0.4", 6379), new HostAndPort("my-redis.example.com", 7002)); Set initialNodes = new HashSet<>(); -initialNodes.add(new HostAndPort("localhost", 7001)); +// seed node +initialNodes.add(new HostAndPort("my-redis.example.com", 7001)); HostAndPortMapper mapper = new DockerNATMapper(nodeMapping); @@ -269,11 +285,12 @@ Since HostAndPortMapper is a functional interface (it has only one abstract meth ```java Map nodeMapping = new HashMap<>(); -nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("localhost", 7001)); -nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("localhost", 7002)); +nodeMapping.put(new HostAndPort("172.18.0.2", 6379), new HostAndPort("my-redis.example.com", 7001)); +nodeMapping.put(new HostAndPort("172.18.0.3", 6379), new HostAndPort("my-redis.example.com", 7002)); +nodeMapping.put(new HostAndPort("172.18.0.4", 6379), new HostAndPort("my-redis.example.com", 7002)); Set initialNodes = new HashSet<>(); -initialNodes.add(new HostAndPort("localhost", 7001)); +initialNodes.add(new HostAndPort("my-redis.example.com", 7001)); HostAndPortMapper mapper = internalAddress -> nodeMapping.getOrDefault(internalAddress, internalAddress); From e7183ecd0efc375d95c7869bd11e971f917210fe Mon Sep 17 00:00:00 2001 From: ggivo Date: Thu, 14 Aug 2025 09:01:19 +0300 Subject: [PATCH 6/6] update wordlist --- .github/wordlist.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 9162dbf797..d16a9dc2e7 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -17,6 +17,7 @@ ClusterPipeline ClusterPubSub ConnectionPool CoreCommands +config Dockerfile EVAL EVALSHA @@ -34,6 +35,7 @@ GeoUnit GraphCommands Grokzen's HostAndPort +HostAndPortMapper HostnameVerifier INCR IOError @@ -83,6 +85,7 @@ RedisInstrumentor RedisJSON RedisTimeSeries Redislabs +reusability SHA SSLParameters SSLSocketFactory @@ -199,6 +202,7 @@ keyspace keysvalues kllayn kwarg +Kubernetes lastName lastsave learningpath