Added a JUnit test for JedisSentinelPool.
This test will set up and get a master from a Redis master slave pair being watched by 2 Sentinels. It pings the master, segfaults it, asks the pool for another connection and makes sure it can ping it. This commit also restores the pom.xml file's scm information back to xetorthio and adds the default Sentinel port to the Procotol.
This commit is contained in:
58
Makefile
58
Makefile
@@ -3,6 +3,7 @@ daemonize yes
|
|||||||
port 6379
|
port 6379
|
||||||
requirepass foobared
|
requirepass foobared
|
||||||
pidfile /tmp/redis1.pid
|
pidfile /tmp/redis1.pid
|
||||||
|
logfile /tmp/redis1.log
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define REDIS2_CONF
|
define REDIS2_CONF
|
||||||
@@ -10,33 +11,86 @@ daemonize yes
|
|||||||
port 6380
|
port 6380
|
||||||
requirepass foobared
|
requirepass foobared
|
||||||
pidfile /tmp/redis2.pid
|
pidfile /tmp/redis2.pid
|
||||||
|
logfile /tmp/redis2.log
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define REDIS3_CONF
|
||||||
|
daemonize yes
|
||||||
|
port 6381
|
||||||
|
pidfile /tmp/redis3.pid
|
||||||
|
logfile /tmp/redis3.log
|
||||||
|
endef
|
||||||
|
|
||||||
|
define REDIS4_CONF
|
||||||
|
daemonize yes
|
||||||
|
port 6382
|
||||||
|
pidfile /tmp/redis4.pid
|
||||||
|
logfile /tmp/redis4.log
|
||||||
|
endef
|
||||||
|
|
||||||
define REDIS_SENTINEL1
|
define REDIS_SENTINEL1
|
||||||
port 26379
|
port 26379
|
||||||
daemonize yes
|
daemonize yes
|
||||||
sentinel monitor mymaster 127.0.0.1 6379 2
|
sentinel monitor mymaster 127.0.0.1 6379 1
|
||||||
sentinel auth-pass mymaster foobared
|
sentinel auth-pass mymaster foobared
|
||||||
sentinel down-after-milliseconds mymaster 5000
|
sentinel down-after-milliseconds mymaster 1000
|
||||||
sentinel failover-timeout mymaster 900000
|
sentinel failover-timeout mymaster 900000
|
||||||
sentinel can-failover mymaster yes
|
sentinel can-failover mymaster yes
|
||||||
sentinel parallel-syncs mymaster 1
|
sentinel parallel-syncs mymaster 1
|
||||||
pidfile /tmp/sentinel1.pid
|
pidfile /tmp/sentinel1.pid
|
||||||
|
logfile /tmp/sentinel1.log
|
||||||
|
endef
|
||||||
|
|
||||||
|
define REDIS_SENTINEL2
|
||||||
|
port 26380
|
||||||
|
daemonize yes
|
||||||
|
sentinel monitor mymaster 127.0.0.1 6381 2
|
||||||
|
sentinel down-after-milliseconds mymaster 3000
|
||||||
|
sentinel can-failover mymaster yes
|
||||||
|
sentinel parallel-syncs mymaster 1
|
||||||
|
sentinel failover-timeout mymaster 900000
|
||||||
|
pidfile /tmp/sentinel2.pid
|
||||||
|
logfile /tmp/sentinel2.log
|
||||||
|
endef
|
||||||
|
|
||||||
|
define REDIS_SENTINEL3
|
||||||
|
port 26381
|
||||||
|
daemonize yes
|
||||||
|
sentinel monitor mymaster 127.0.0.1 6381 2
|
||||||
|
sentinel down-after-milliseconds mymaster 3000
|
||||||
|
sentinel can-failover mymaster yes
|
||||||
|
sentinel parallel-syncs mymaster 1
|
||||||
|
sentinel failover-timeout mymaster 900000
|
||||||
|
pidfile /tmp/sentinel3.pid
|
||||||
|
logfile /tmp/sentinel3.log
|
||||||
endef
|
endef
|
||||||
|
|
||||||
export REDIS1_CONF
|
export REDIS1_CONF
|
||||||
export REDIS2_CONF
|
export REDIS2_CONF
|
||||||
|
export REDIS3_CONF
|
||||||
|
export REDIS4_CONF
|
||||||
export REDIS_SENTINEL1
|
export REDIS_SENTINEL1
|
||||||
|
export REDIS_SENTINEL2
|
||||||
|
export REDIS_SENTINEL3
|
||||||
|
|
||||||
test:
|
test:
|
||||||
echo "$$REDIS1_CONF" | redis-server -
|
echo "$$REDIS1_CONF" | redis-server -
|
||||||
echo "$$REDIS2_CONF" | redis-server -
|
echo "$$REDIS2_CONF" | redis-server -
|
||||||
|
echo "$$REDIS3_CONF" | redis-server -
|
||||||
|
echo "$$REDIS4_CONF" | redis-server -
|
||||||
echo "$$REDIS_SENTINEL1" | redis-sentinel -
|
echo "$$REDIS_SENTINEL1" | redis-sentinel -
|
||||||
|
echo "$$REDIS_SENTINEL2" | redis-sentinel -
|
||||||
|
echo "$$REDIS_SENTINEL3" | redis-sentinel -
|
||||||
|
|
||||||
mvn clean compile test
|
mvn clean compile test
|
||||||
|
|
||||||
kill `cat /tmp/redis1.pid`
|
kill `cat /tmp/redis1.pid`
|
||||||
kill `cat /tmp/redis2.pid`
|
kill `cat /tmp/redis2.pid`
|
||||||
|
# this get's segfaulted by the tests
|
||||||
|
kill `cat /tmp/redis3.pid` || true
|
||||||
|
kill `cat /tmp/redis4.pid`
|
||||||
kill `cat /tmp/sentinel1.pid`
|
kill `cat /tmp/sentinel1.pid`
|
||||||
|
kill `cat /tmp/sentinel2.pid`
|
||||||
|
kill `cat /tmp/sentinel3.pid`
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
|
|||||||
15
pom.xml
15
pom.xml
@@ -13,7 +13,7 @@
|
|||||||
<version>2.2.2-SNAPSHOT</version>
|
<version>2.2.2-SNAPSHOT</version>
|
||||||
<name>Jedis</name>
|
<name>Jedis</name>
|
||||||
<description>Jedis is a blazingly small and sane Redis java client.</description>
|
<description>Jedis is a blazingly small and sane Redis java client.</description>
|
||||||
<url>https://github.com/mardambey/jedis</url>
|
<url>https://github.com/xetorthio/jedis</url>
|
||||||
|
|
||||||
<mailingLists>
|
<mailingLists>
|
||||||
<mailingList>
|
<mailingList>
|
||||||
@@ -28,24 +28,25 @@
|
|||||||
<licenses>
|
<licenses>
|
||||||
<license>
|
<license>
|
||||||
<name>MIT</name>
|
<name>MIT</name>
|
||||||
<url>http://github.com/mardambey/jedis/raw/master/LICENSE.txt</url>
|
<url>http://github.com/xetorthio/jedis/raw/master/LICENSE.txt</url>
|
||||||
<distribution>repo</distribution>
|
<distribution>repo</distribution>
|
||||||
</license>
|
</license>
|
||||||
</licenses>
|
</licenses>
|
||||||
|
|
||||||
<issueManagement>
|
<issueManagement>
|
||||||
<system>github</system>
|
<system>github</system>
|
||||||
<url>http://github.com/mardambey/jedis/issues</url>
|
<url>http://github.com/xetorthio/jedis/issues</url>
|
||||||
</issueManagement>
|
</issueManagement>
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<connection>scm:git:git@github.com:mardambey/jedis.git</connection>
|
<connection>scm:git:git@github.com:xetorthio/jedis.git</connection>
|
||||||
<url>scm:git:git@github.com:mardambey/jedis.git</url>
|
<url>scm:git:git@github.com:xetorthio/jedis.git</url>
|
||||||
<developerConnection>scm:git:git@github.com:mardambey/jedis.git</developerConnection>
|
<developerConnection>scm:git:git@github.com:xetorthio/jedis.git</developerConnection>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<redis-hosts>localhost:6379,localhost:6380</redis-hosts>
|
<redis-hosts>localhost:6379,localhost:6380,localhost:6381,localhost:6382</redis-hosts>
|
||||||
|
<sentinel-hosts>localhost:26379,localhost:26380</sentinel-hosts>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|||||||
@@ -231,9 +231,13 @@ public class JedisSentinelPool extends Pool<Jedis> {
|
|||||||
}, "+switch-master");
|
}, "+switch-master");
|
||||||
|
|
||||||
} catch (JedisConnectionException e) {
|
} catch (JedisConnectionException e) {
|
||||||
log.severe("Lost connection to Sentinel at " + host + ":" + port + ". Sleeping 5000ms and retrying.");
|
|
||||||
|
|
||||||
try { Thread.sleep(subscribeRetryWaitTimeMillis); } catch (InterruptedException e1) { e1.printStackTrace(); }
|
if (running.get()) {
|
||||||
|
log.severe("Lost connection to Sentinel at " + host + ":" + port + ". Sleeping 5000ms and retrying.");
|
||||||
|
try { Thread.sleep(subscribeRetryWaitTimeMillis); } catch (InterruptedException e1) { e1.printStackTrace(); }
|
||||||
|
} else {
|
||||||
|
log.fine("Unsubscribing from Sentinel at " + host + ":" + port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import redis.clients.util.SafeEncoder;
|
|||||||
public final class Protocol {
|
public final class Protocol {
|
||||||
|
|
||||||
public static final int DEFAULT_PORT = 6379;
|
public static final int DEFAULT_PORT = 6379;
|
||||||
|
public static final int DEFAULT_SENTINEL_PORT = 26379;
|
||||||
public static final int DEFAULT_TIMEOUT = 2000;
|
public static final int DEFAULT_TIMEOUT = 2000;
|
||||||
public static final int DEFAULT_DATABASE = 0;
|
public static final int DEFAULT_DATABASE = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -6,56 +6,104 @@ import java.util.List;
|
|||||||
import redis.clients.jedis.Protocol;
|
import redis.clients.jedis.Protocol;
|
||||||
|
|
||||||
public class HostAndPortUtil {
|
public class HostAndPortUtil {
|
||||||
private static List<HostAndPort> hostAndPortList = new ArrayList<HostAndPortUtil.HostAndPort>(
|
private static List<HostAndPort> redisHostAndPortList = new ArrayList<HostAndPortUtil.HostAndPort>();
|
||||||
2);
|
private static List<HostAndPort> sentinelHostAndPortList = new ArrayList<HostAndPortUtil.HostAndPort>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final HostAndPort defaulthnp1 = new HostAndPort();
|
|
||||||
|
HostAndPort defaulthnp1 = new HostAndPort();
|
||||||
defaulthnp1.host = "localhost";
|
defaulthnp1.host = "localhost";
|
||||||
defaulthnp1.port = Protocol.DEFAULT_PORT;
|
defaulthnp1.port = Protocol.DEFAULT_PORT;
|
||||||
hostAndPortList.add(defaulthnp1);
|
redisHostAndPortList.add(defaulthnp1);
|
||||||
|
|
||||||
final HostAndPort defaulthnp2 = new HostAndPort();
|
HostAndPort defaulthnp2 = new HostAndPort();
|
||||||
defaulthnp2.host = "localhost";
|
defaulthnp2.host = "localhost";
|
||||||
defaulthnp2.port = Protocol.DEFAULT_PORT + 1;
|
defaulthnp2.port = Protocol.DEFAULT_PORT + 1;
|
||||||
hostAndPortList.add(defaulthnp2);
|
redisHostAndPortList.add(defaulthnp2);
|
||||||
|
|
||||||
|
HostAndPort defaulthnp3 = new HostAndPort();
|
||||||
|
defaulthnp3.host = "localhost";
|
||||||
|
defaulthnp3.port = Protocol.DEFAULT_PORT + 2;
|
||||||
|
redisHostAndPortList.add(defaulthnp3);
|
||||||
|
|
||||||
|
HostAndPort defaulthnp4 = new HostAndPort();
|
||||||
|
defaulthnp4.host = "localhost";
|
||||||
|
defaulthnp4.port = Protocol.DEFAULT_PORT + 3;
|
||||||
|
redisHostAndPortList.add(defaulthnp4);
|
||||||
|
|
||||||
|
HostAndPort defaulthnp5 = new HostAndPort();
|
||||||
|
defaulthnp5.host = "localhost";
|
||||||
|
defaulthnp5.port = Protocol.DEFAULT_SENTINEL_PORT;
|
||||||
|
sentinelHostAndPortList.add(defaulthnp5);
|
||||||
|
|
||||||
|
HostAndPort defaulthnp6 = new HostAndPort();
|
||||||
|
defaulthnp6.host = "localhost";
|
||||||
|
defaulthnp6.port = Protocol.DEFAULT_SENTINEL_PORT + 1;
|
||||||
|
sentinelHostAndPortList.add(defaulthnp6);
|
||||||
|
|
||||||
|
HostAndPort defaulthnp7 = new HostAndPort();
|
||||||
|
defaulthnp7.host = "localhost";
|
||||||
|
defaulthnp7.port = Protocol.DEFAULT_SENTINEL_PORT + 2;
|
||||||
|
sentinelHostAndPortList.add(defaulthnp7);
|
||||||
|
|
||||||
final String envHosts = System.getProperty("redis-hosts");
|
String envRedisHosts = System.getProperty("redis-hosts");
|
||||||
if (null != envHosts && 0 < envHosts.length()) {
|
String envSentinelHosts = System.getProperty("sentinel-hosts");
|
||||||
final String[] hostDefs = envHosts.split(",");
|
|
||||||
|
redisHostAndPortList = parseHosts(envRedisHosts, redisHostAndPortList);
|
||||||
|
sentinelHostAndPortList = parseHosts(envSentinelHosts, sentinelHostAndPortList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<HostAndPort> parseHosts(String envHosts, List<HostAndPort> existingHostsAndPorts) {
|
||||||
|
|
||||||
|
if (null != envHosts && 0 < envHosts.length()) {
|
||||||
|
|
||||||
|
String[] hostDefs = envHosts.split(",");
|
||||||
|
|
||||||
if (null != hostDefs && 2 <= hostDefs.length) {
|
if (null != hostDefs && 2 <= hostDefs.length) {
|
||||||
hostAndPortList = new ArrayList<HostAndPortUtil.HostAndPort>(
|
|
||||||
hostDefs.length);
|
List<HostAndPort> envHostsAndPorts = new ArrayList<HostAndPortUtil.HostAndPort>(hostDefs.length);
|
||||||
|
|
||||||
for (String hostDef : hostDefs) {
|
for (String hostDef : hostDefs) {
|
||||||
final String[] hostAndPort = hostDef.split(":");
|
|
||||||
|
String[] hostAndPort = hostDef.split(":");
|
||||||
|
|
||||||
if (null != hostAndPort && 2 == hostAndPort.length) {
|
if (null != hostAndPort && 2 == hostAndPort.length) {
|
||||||
final HostAndPort hnp = new HostAndPort();
|
|
||||||
|
HostAndPort hnp = new HostAndPort();
|
||||||
hnp.host = hostAndPort[0];
|
hnp.host = hostAndPort[0];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
hnp.port = Integer.parseInt(hostAndPort[1]);
|
hnp.port = Integer.parseInt(hostAndPort[1]);
|
||||||
} catch (final NumberFormatException nfe) {
|
} catch (final NumberFormatException nfe) {
|
||||||
hnp.port = Protocol.DEFAULT_PORT;
|
hnp.port = Protocol.DEFAULT_PORT;
|
||||||
}
|
}
|
||||||
hostAndPortList.add(hnp);
|
|
||||||
|
envHostsAndPorts.add(hnp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return envHostsAndPorts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final StringBuilder strb = new StringBuilder(
|
|
||||||
"Redis hosts to be used : ");
|
return existingHostsAndPorts;
|
||||||
for (HostAndPort hnp : hostAndPortList) {
|
|
||||||
strb.append('[').append(hnp.host).append(':').append(hnp.port)
|
|
||||||
.append(']').append(' ');
|
|
||||||
}
|
|
||||||
System.out.println(strb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<HostAndPort> getRedisServers() {
|
public static List<HostAndPort> getRedisServers() {
|
||||||
return hostAndPortList;
|
return redisHostAndPortList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<HostAndPort> getSentinelServers() {
|
||||||
|
return sentinelHostAndPortList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HostAndPort {
|
public static class HostAndPort {
|
||||||
public String host;
|
public String host;
|
||||||
public int port;
|
public int port;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return host + ":" + port;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package redis.clients.jedis.tests;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import redis.clients.jedis.DebugParams;
|
||||||
|
import redis.clients.jedis.Jedis;
|
||||||
|
import redis.clients.jedis.JedisSentinelPool;
|
||||||
|
import redis.clients.jedis.tests.HostAndPortUtil.HostAndPort;
|
||||||
|
|
||||||
|
public class JedisSentinelPoolTest extends JedisTestBase {
|
||||||
|
|
||||||
|
protected static HostAndPort master = HostAndPortUtil.getRedisServers().get(2);
|
||||||
|
protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers().get(3);
|
||||||
|
protected static HostAndPort sentinel1 = HostAndPortUtil.getSentinelServers().get(1);
|
||||||
|
protected static HostAndPort sentinel2 = HostAndPortUtil.getSentinelServers().get(2);
|
||||||
|
|
||||||
|
protected static Jedis masterJedis;
|
||||||
|
protected static Jedis slaveJedis1;
|
||||||
|
protected static Jedis sentinelJedis1;
|
||||||
|
|
||||||
|
protected Set<String> sentinels = new HashSet<String>();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
|
// set up master and slaves
|
||||||
|
masterJedis = new Jedis(master.host, master.port);
|
||||||
|
masterJedis.slaveofNoOne();
|
||||||
|
|
||||||
|
slaveJedis1 = new Jedis(slave1.host, slave1.port);
|
||||||
|
slaveJedis1.slaveof(master.host, master.port);
|
||||||
|
|
||||||
|
sentinelJedis1 = new Jedis(sentinel1.host, sentinel1.port);
|
||||||
|
sentinels.add(sentinel1.toString());
|
||||||
|
sentinels.add(sentinel2.toString());
|
||||||
|
|
||||||
|
// FIXME: The following allows the master/slave relationship to
|
||||||
|
// be established. We can do this more elegantly.
|
||||||
|
Thread.sleep(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void segfaultMaster() throws InterruptedException {
|
||||||
|
|
||||||
|
JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels);
|
||||||
|
|
||||||
|
Jedis jedis = pool.getResource();
|
||||||
|
assertEquals("PONG", jedis.ping());
|
||||||
|
|
||||||
|
try { masterJedis.debug(DebugParams.SEGFAULT()); } catch (Exception e) {}
|
||||||
|
|
||||||
|
// wait for the sentinel to promote a master
|
||||||
|
// FIXME: we can query the sentinel and sleep
|
||||||
|
// right until the master is promoted
|
||||||
|
Thread.sleep(35000);
|
||||||
|
|
||||||
|
jedis = pool.getResource();
|
||||||
|
assertEquals("PONG", jedis.ping());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,7 +49,7 @@ public class JedisSentinelTest {
|
|||||||
assertEquals("6379", masterHostAndPort.get(1));
|
assertEquals("6379", masterHostAndPort.get(1));
|
||||||
|
|
||||||
List<Map<String, String>> slaves = j.sentinelSlaves(masterName);
|
List<Map<String, String>> slaves = j.sentinelSlaves(masterName);
|
||||||
assertEquals(1, slaves.size());
|
assertTrue(slaves.size() > 0);
|
||||||
assertEquals("6379", slaves.get(0).get("master-port"));
|
assertEquals("6379", slaves.get(0).get("master-port"));
|
||||||
|
|
||||||
List<? extends Object> isMasterDownByAddr = j
|
List<? extends Object> isMasterDownByAddr = j
|
||||||
|
|||||||
Reference in New Issue
Block a user