Fix race condition in JedisSentinelPoolTest

The test was issuing the failover command and only afterwards
connecting to the pub-sub channel to receive failover notifications.
If the failover occurred fast enought the pub-sub listener would never
get the notification.

Run the failover command on a separate Jedis connection after we're
absolutely sure that we're subscribed to the pub-sub channel.
This commit is contained in:
Nelson Rodrigues
2014-07-28 10:56:21 -07:00
parent 9e128b4520
commit 9013078d40
3 changed files with 11 additions and 7 deletions

View File

@@ -23,6 +23,7 @@ public class HostAndPortUtil {
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 1));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2)); sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 2));
sentinelHostAndPortList.add(new HostAndPort("localhost", Protocol.DEFAULT_SENTINEL_PORT + 3));
clusterHostAndPortList.add(new HostAndPort("localhost", 7379)); clusterHostAndPortList.add(new HostAndPort("localhost", 7379));
clusterHostAndPortList.add(new HostAndPort("localhost", 7380)); clusterHostAndPortList.add(new HostAndPort("localhost", 7380));

View File

@@ -21,18 +21,24 @@ public class JedisSentinelPoolTest extends JedisTestBase {
.get(2); .get(2);
protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers() protected static HostAndPort slave1 = HostAndPortUtil.getRedisServers()
.get(3); .get(3);
protected static HostAndPort sentinel1 = HostAndPortUtil protected static HostAndPort sentinel1 = HostAndPortUtil
.getSentinelServers().get(1); .getSentinelServers().get(1);
protected static HostAndPort sentinel2 = HostAndPortUtil
.getSentinelServers().get(3);
protected static Jedis sentinelJedis1; protected static Jedis sentinelJedis1;
protected static Jedis sentinelJedis2;
protected Set<String> sentinels = new HashSet<String>(); protected Set<String> sentinels = new HashSet<String>();
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
sentinels.add(sentinel1.toString()); sentinels.add(sentinel1.toString());
sentinels.add(sentinel2.toString());
sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort()); sentinelJedis1 = new Jedis(sentinel1.getHost(), sentinel1.getPort());
sentinelJedis2 = new Jedis(sentinel2.getHost(), sentinel2.getPort());
} }
@Test @Test
@@ -137,11 +143,6 @@ public class JedisSentinelPoolTest extends JedisTestBase {
Jedis jedis = pool.getResource(); Jedis jedis = pool.getResource();
assertEquals("PONG", jedis.ping()); assertEquals("PONG", jedis.ping());
// It can throw JedisDataException while there's no slave to promote
// There's nothing we can do, so we just pass Exception to make test
// fail fast
sentinelJedis1.sentinelFailover(MASTER_NAME);
waitForFailover(pool, oldMaster); waitForFailover(pool, oldMaster);
// JedisSentinelPool recognize master but may not changed internal pool // JedisSentinelPool recognize master but may not changed internal pool
// yet // yet
@@ -156,7 +157,7 @@ public class JedisSentinelPoolTest extends JedisTestBase {
private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster) private void waitForFailover(JedisSentinelPool pool, HostAndPort oldMaster)
throws InterruptedException { throws InterruptedException {
HostAndPort newMaster = JedisSentinelTestUtil HostAndPort newMaster = JedisSentinelTestUtil
.waitForNewPromotedMaster(sentinelJedis1); .waitForNewPromotedMaster(MASTER_NAME, sentinelJedis1, sentinelJedis2);
waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster); waitForJedisSentinelPoolRecognizeNewMaster(pool, newMaster);
} }

View File

@@ -8,7 +8,8 @@ import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.tests.utils.FailoverAbortedException; import redis.clients.jedis.tests.utils.FailoverAbortedException;
public class JedisSentinelTestUtil { public class JedisSentinelTestUtil {
public static HostAndPort waitForNewPromotedMaster(Jedis sentinelJedis) public static HostAndPort waitForNewPromotedMaster(final String masterName,
final Jedis sentinelJedis, final Jedis commandJedis)
throws InterruptedException { throws InterruptedException {
final AtomicReference<String> newmaster = new AtomicReference<String>( final AtomicReference<String> newmaster = new AtomicReference<String>(
@@ -47,6 +48,7 @@ public class JedisSentinelTestUtil {
@Override @Override
public void onPSubscribe(String pattern, int subscribedChannels) { public void onPSubscribe(String pattern, int subscribedChannels) {
commandJedis.sentinelFailover(masterName);
} }
}, "*"); }, "*");