All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.redis.impl.RedisMasterResolver Maven / Gradle / Ivy

The newest version!
package io.vertx.redis.impl;

import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.redis.RedisOptions;
import io.vertx.redis.sentinel.RedisSentinel;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Use this class to resolve the address of the Redis master using Sentinel servers.
 */
class RedisMasterResolver {

  private static final Logger log = LoggerFactory.getLogger(RedisMasterResolver.class);

  private static final int MAX_WAIT_FOR_MASTER_IN_MILLIS = 3000;

  private List sentinels = new ArrayList<>();
  private String masterName;

  private Vertx vertx;

  RedisMasterResolver(Vertx vertx, RedisOptions redisOptions) {

    this.vertx = vertx;
    this.masterName = redisOptions.getMasterName();
    redisOptions.getSentinels().forEach(s -> {
      String[] hostAndPort = s.split(":");
      if (hostAndPort.length == 2) {
        sentinels.add(RedisSentinel.create(vertx, getSentinelOptions(redisOptions, hostAndPort[0], Integer.valueOf(hostAndPort[1]))));
      } else {
        sentinels.add(RedisSentinel.create(vertx, getSentinelOptions(redisOptions, hostAndPort[0], 6379)));
      }
    });
  }

  void getMasterAddressByName(Handler> handler) {

    log.debug("Attempting to resolving master address");

    try {

      AtomicInteger count = new AtomicInteger(sentinels.size());
      AtomicBoolean foundMaster = new AtomicBoolean(false);

      // Try get a master from any sentinel
      for (RedisSentinel sentinelClient : sentinels) {

        // Set up handler
        Handler> asyncResultHandler = jsonObjectAsyncResult -> {
          count.decrementAndGet();
          if (jsonObjectAsyncResult.succeeded()) {
            JsonArray masterArray = jsonObjectAsyncResult.result();
            if (masterArray != null && masterArray.size() == 2) {
              JsonObject redisMaster = new JsonObject().put("host", masterArray.getString(0)).put("port", Integer.valueOf(masterArray.getString(1)));
              if (!foundMaster.get()) {
                log.info(String.format("Sentinel resolved address for master '%s' to %s:%d", masterName, masterArray.getString(0), Integer.valueOf(masterArray.getString(1))));
                foundMaster.set(true);
                handler.handle(Future.factory.succeededFuture(redisMaster));
              }
            } else {
              handler.handle(Future.failedFuture(String.format("Sentinel failed to resolve address for master '%s'", masterName)));
            }
          } else {
            handler.handle(Future.failedFuture(String.format("Sentinel unreachable. %s", jsonObjectAsyncResult.cause().getMessage())));
          }

          if (count.get() == 0 && !foundMaster.get()) {
            handler.handle(Future.failedFuture("Failed to resolve master address"));
          }
        };

        // Set up timer for timeout
        final long timerId = vertx.setTimer(MAX_WAIT_FOR_MASTER_IN_MILLIS, t -> asyncResultHandler.handle(Future.failedFuture("Timeout on response from Sentinel")));

        // Handle the response
        sentinelClient.getMasterAddrByName(masterName, res -> {
          // Check if timer triggered
          if (vertx.cancelTimer(timerId)) {
            asyncResultHandler.handle(res);
          }
        });
      }
    } catch (Exception ex) {
      handler.handle(Future.factory.failedFuture(ex));
    }
  }

  private RedisOptions getSentinelOptions(RedisOptions redisOptions, String host, int port) {
    // copy the base config
    RedisOptions options = new RedisOptions(redisOptions);
    // override the host and port
    options.setHost(host);
    options.setPort(port);

    return options;
  }

  void close() {
    for (RedisSentinel sentinel : sentinels) {
      sentinel.close(h -> {});
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy