diff --git a/src/main/java/org/swisspush/reststorage/DefaultRedisProvider.java b/src/main/java/org/swisspush/reststorage/DefaultRedisProvider.java index af8ef23..62a3831 100644 --- a/src/main/java/org/swisspush/reststorage/DefaultRedisProvider.java +++ b/src/main/java/org/swisspush/reststorage/DefaultRedisProvider.java @@ -8,12 +8,13 @@ import io.vertx.redis.client.RedisConnection; import io.vertx.redis.client.RedisClientType; import io.vertx.redis.client.RedisOptions; -import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.swisspush.reststorage.redis.RedisProvider; import org.swisspush.reststorage.util.ModuleConfiguration; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -95,19 +96,19 @@ private Future connectToRedis() { .setMaxPoolSize(redisMaxPoolSize) .setMaxPoolWaiting(redisMaxPoolWaitingSize) .setPoolRecycleTimeout(redisPoolRecycleTimeoutMs) - .setMaxWaitingHandlers(redisMaxPipelineWaitingSize); - if (configuration.isRedisClustered()) { - redisOptions.setType(RedisClientType.CLUSTER); - redisOptions.addConnectionString(createConnectString()); - } else { - redisOptions.setConnectionString(createConnectString()); - } + .setMaxWaitingHandlers(redisMaxPipelineWaitingSize) + .setType(configuration.getRedisClientType()); + + createConnectStrings().forEach(redisOptions::addConnectionString); redis = Redis.createClient(vertx, redisOptions); redis.connect().onSuccess(conn -> { log.info("Successfully connected to redis"); client = conn; - client.close(); + + if (configuration.getRedisClientType() == RedisClientType.STANDALONE) { + client.close(); + } // make sure the client is reconnected on error // eg, the underlying TCP connection is closed but the client side doesn't know it yet @@ -138,16 +139,22 @@ private Future connectToRedis() { return promise.future(); } - private String createConnectString() { - StringBuilder connectionStringBuilder = new StringBuilder(); - connectionStringBuilder.append(configuration.isRedisEnableTls() ? "rediss://" : "redis://"); - String redisUser = configuration.getRedisUser(); + private List createConnectStrings() { String redisPassword = configuration.getRedisPassword(); - if (StringUtils.isNotEmpty(redisUser) && StringUtils.isNotEmpty(redisPassword)) { - connectionStringBuilder.append(configuration.getRedisUser()).append(":").append(redisPassword).append("@"); + String redisUser = configuration.getRedisUser(); + StringBuilder connectionStringPrefixBuilder = new StringBuilder(); + connectionStringPrefixBuilder.append(configuration.isRedisEnableTls() ? "rediss://" : "redis://"); + if (redisUser != null && !redisUser.isEmpty()) { + connectionStringPrefixBuilder.append(redisUser).append(":").append((redisPassword == null ? "" : redisPassword)).append("@"); + } + List connectionString = new ArrayList<>(); + String connectionStringPrefix = connectionStringPrefixBuilder.toString(); + for (int i = 0; i < configuration.getRedisHosts().size(); i++) { + String host = configuration.getRedisHosts().get(i); + int port = configuration.getRedisPorts().get(i); + connectionString.add(connectionStringPrefix + host + ":" + port); } - connectionStringBuilder.append(configuration.getRedisHost()).append(":").append(configuration.getRedisPort()); - return connectionStringBuilder.toString(); + return connectionString; } private void attemptReconnect(int retry) { diff --git a/src/main/java/org/swisspush/reststorage/util/ModuleConfiguration.java b/src/main/java/org/swisspush/reststorage/util/ModuleConfiguration.java index f4b96d9..d0bdad5 100644 --- a/src/main/java/org/swisspush/reststorage/util/ModuleConfiguration.java +++ b/src/main/java/org/swisspush/reststorage/util/ModuleConfiguration.java @@ -1,9 +1,13 @@ package org.swisspush.reststorage.util; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.vertx.core.json.JsonObject; +import io.vertx.redis.client.RedisClientType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -11,6 +15,7 @@ * * @author https://github.com/mcweba [Marc-Andre Weber] */ +@JsonIgnoreProperties(ignoreUnknown = true) public class ModuleConfiguration { private static final Logger log = LoggerFactory.getLogger(ModuleConfiguration.class); @@ -29,10 +34,11 @@ public enum StorageType { private String prefix = ""; private String storageAddress = "resource-storage"; private Map editorConfig = null; - private String redisHost = "localhost"; - private int redisPort = 6379; + private List redisHosts = Collections.singletonList("localhost"); + private List redisPorts = Collections.singletonList(6379); private boolean redisEnableTls; - private boolean redisClustered; + private RedisClientType redisClientType = RedisClientType.STANDALONE; + /** * @deprecated Instance authentication is considered as legacy. With Redis from 6.x on the ACL authentication method should be used. */ @@ -116,12 +122,22 @@ public ModuleConfiguration editorConfig(Map editorConfig) { } public ModuleConfiguration redisHost(String redisHost) { - this.redisHost = redisHost; + this.redisHosts = Collections.singletonList(redisHost); return this; } public ModuleConfiguration redisPort(int redisPort) { - this.redisPort = redisPort; + this.redisPorts = Collections.singletonList(redisPort); + return this; + } + + public ModuleConfiguration redisHosts(List redisHosts) { + this.redisHosts = redisHosts; + return this; + } + + public ModuleConfiguration redisPorts(List redisPorts) { + this.redisPorts = redisPorts; return this; } @@ -130,8 +146,8 @@ public ModuleConfiguration redisEnableTls(boolean redisEnableTls) { return this; } - public ModuleConfiguration redisClustered(boolean redisClustered) { - this.redisClustered = redisClustered; + public ModuleConfiguration redisClientType(RedisClientType redisClientType) { + this.redisClientType = redisClientType; return this; } @@ -287,11 +303,18 @@ public Map getEditorConfig() { } public String getRedisHost() { - return redisHost; + return redisHosts.get(0); + } + + public List getRedisHosts() { + return redisHosts; } public int getRedisPort() { - return redisPort; + return redisPorts.get(0); + } + public List getRedisPorts() { + return redisPorts; } public int getRedisReconnectAttempts() { @@ -314,10 +337,6 @@ public boolean isRedisEnableTls() { return redisEnableTls; } - public boolean isRedisClustered() { - return redisClustered; - } - public String getRedisAuth() { return redisAuth; } @@ -329,7 +348,9 @@ public String getRedisPassword() { public String getRedisUser() { return redisUser; } - + public RedisClientType getRedisClientType() { + return redisClientType; + } public String getExpirablePrefix() { return expirablePrefix; } diff --git a/src/test/java/org/swisspush/reststorage/util/ModuleConfigurationTest.java b/src/test/java/org/swisspush/reststorage/util/ModuleConfigurationTest.java index 2bc8899..33037aa 100644 --- a/src/test/java/org/swisspush/reststorage/util/ModuleConfigurationTest.java +++ b/src/test/java/org/swisspush/reststorage/util/ModuleConfigurationTest.java @@ -6,6 +6,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Collections; import java.util.HashMap; import static org.swisspush.reststorage.util.ModuleConfiguration.StorageType; @@ -272,8 +273,8 @@ public void testGetOverriddenFromJsonObject(TestContext testContext){ json.put("prefix", "newprefix"); json.put("storageAddress", "newStorageAddress"); json.put("editorConfig", new JsonObject().put("myKey", "myValue")); - json.put("redisHost", "newredishost"); - json.put("redisPort", 4321); + json.put("redisHosts", Collections.singletonList("newredishost")); + json.put("redisPorts", Collections.singletonList(4321)); json.put("maxRedisWaitingHandlers", 4096); json.put("expirablePrefix", "newExpirablePrefix"); json.put("resourcesPrefix", "newResourcesPrefix");