Accept cluster nodes without hostname.

RedisNode can now be constructed using an empty hostname. This can happen when a node is in failover state. RedisNode exposes hasValidHost() to check whether the node has a valid hostname.

Also, introduce copy constructor to avoid mutations caused by the builder.

Closes #1985
Original Pull Request: #1991
This commit is contained in:
Mark Paluch
2021-03-03 14:39:43 +01:00
committed by Christoph Strobl
parent b8eabee2b0
commit b5ea3f6826
6 changed files with 69 additions and 4 deletions

View File

@@ -197,11 +197,11 @@ public class ClusterTopology {
Assert.notNull(node, "RedisClusterNode must not be null!");
if (nodes.contains(node) && StringUtils.hasText(node.getHost()) && StringUtils.hasText(node.getId())) {
if (nodes.contains(node) && node.hasValidHost() && StringUtils.hasText(node.getId())) {
return node;
}
if (StringUtils.hasText(node.getHost()) && node.getPort() != null) {
if (node.hasValidHost() && node.getPort() != null) {
return lookup(node.getHost(), node.getPort());
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.redis.connection;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* @author Christoph Strobl
@@ -50,6 +51,16 @@ public class RedisNode implements NamedNode {
protected RedisNode() {}
private RedisNode(RedisNode redisNode) {
this.id = redisNode.id;
this.name = redisNode.name;
this.host = redisNode.host;
this.port = redisNode.port;
this.type = redisNode.type;
this.masterId = redisNode.masterId;
}
/**
* @return can be {@literal null}.
*/
@@ -58,6 +69,14 @@ public class RedisNode implements NamedNode {
return host;
}
/**
* @return whether this node has a valid host (not null and not empty).
* @since 2.3.8
*/
public boolean hasValidHost() {
return StringUtils.hasText(host);
}
/**
* @return can be {@literal null}.
*/
@@ -229,7 +248,7 @@ public class RedisNode implements NamedNode {
*/
public RedisNodeBuilder listeningAt(String host, int port) {
Assert.hasText(host, "Hostname must not be empty or null.");
Assert.notNull(host, "Hostname must not be null.");
node.host = host;
node.port = port;
return this;
@@ -290,7 +309,7 @@ public class RedisNode implements NamedNode {
* @return
*/
public RedisNode build() {
return this.node;
return new RedisNode(this.node);
}
}

View File

@@ -554,6 +554,7 @@ abstract public class Converters {
static final int LINK_STATE_INDEX = 7;
static final int SLOTS_INDEX = 8;
@Override
public RedisClusterNode convert(String source) {
String[] args = source.split(" ");

View File

@@ -951,6 +951,11 @@ public class JedisClusterConnection implements DefaultedRedisClusterConnection {
RedisClusterNode member = topologyProvider.getTopology().lookup(node);
if (!member.hasValidHost()) {
throw new DataAccessResourceFailureException(String
.format("Cannot obtain connection to node %ss as it is not associated with a hostname!", node.getId()));
}
if (member != null && connectionHandler != null) {
return connectionHandler.getConnectionFromNode(new HostAndPort(member.getHost(), member.getPort()));
}