in iep-spring-leader-redis-cluster/src/main/java/com/netflix/iep/leader/redis/RedisClusterLeaderDatabase.java [92:150]
public boolean updateLeadershipFor(ResourceId resourceId) {
// note slight race here where the follower could overtake the leader if it fails. In that
// case, the watch and transaction should fail and we'd return a false.
String key = getKey(resourceId);
int slot = JedisClusterCRC16.getSlot(key);
try {
try (Jedis client = jedis.leaderForSlot(slot)) {
String watchResult = client.watch(key);
if (watchResult == null || !watchResult.equals("OK")) {
logger.warn("Invalid watch response: {}", watchResult);
return false;
}
try {
String data = client.get(key);
if (data != null && data.equals(leaderString)) {
Transaction transaction = client.multi();
transaction.set(key, leaderString, updateParams);
List<Object> results = transaction.exec();
if (results != null &&
results.size() > 0 &&
results.get(0) != null &&
results.get(0).equals("OK")) {
data = client.get(key);
if (data == null || !data.equals(leaderString)) {
logger.warn("Successfully executed renewal transaction but leader " +
"was still {}", data);
return false;
} else {
logger.debug("Updated leader key {}", key);
return true;
}
} else {
// fall-through
logger.debug("Unable to update our leader status. Trying to capture again.");
}
}
return tryToAcquire(client, key);
} catch (Exception ex) {
logger.error("Unexpected exception updating leadership key: {}", key, ex);
return false;
} finally {
// transactions unset the watch but we also have a get() call before the
// transaction so we need to make sure to release that watch just in case
// something goes wrong between the get parsing and transaction execution.
String unwatchResult = client.unwatch();
if (unwatchResult == null || !unwatchResult.equals("OK")) {
logger.warn("Failure unwatching: {}", unwatchResult);
}
}
}
} catch (Exception ex) {
logger.error("Unexpected exception updating leadership key: {}", key, ex);
return false;
}
}