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

io.lettuce.core.masterreplica.MasterReplicaTopologyRefresh Maven / Gradle / Ivy

Go to download

Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and much more.

The newest version!
package io.lettuce.core.masterreplica;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ScheduledExecutorService;

import reactor.core.publisher.Mono;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisConnectionException;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.cluster.models.partitions.Partitions;
import io.lettuce.core.codec.StringCodec;
import io.lettuce.core.internal.LettuceLists;
import io.lettuce.core.models.role.RedisNodeDescription;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * Utility to refresh the Master-Replica topology view based on {@link RedisNodeDescription}.
 *
 * @author Mark Paluch
 */
class MasterReplicaTopologyRefresh {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(MasterReplicaTopologyRefresh.class);

    private static final StringCodec CODEC = StringCodec.UTF8;

    private final NodeConnectionFactory nodeConnectionFactory;

    private final TopologyProvider topologyProvider;

    private final ScheduledExecutorService eventExecutors;

    MasterReplicaTopologyRefresh(RedisClient client, TopologyProvider topologyProvider) {
        this(new RedisClientNodeConnectionFactory(client), client.getResources().eventExecutorGroup(), topologyProvider);
    }

    MasterReplicaTopologyRefresh(NodeConnectionFactory nodeConnectionFactory, ScheduledExecutorService eventExecutors,
            TopologyProvider topologyProvider) {

        this.nodeConnectionFactory = nodeConnectionFactory;
        this.eventExecutors = eventExecutors;
        this.topologyProvider = topologyProvider;
    }

    /**
     * Load master replica nodes. Result contains an ordered list of {@link RedisNodeDescription}s. The sort key is the latency.
     * Nodes with lower latency come first.
     *
     * @param seed collection of {@link RedisURI}s
     * @return mapping between {@link RedisURI} and {@link Partitions}
     */
    public Mono> getNodes(RedisURI seed) {

        CompletableFuture> future = topologyProvider.getNodesAsync();

        Mono> initialNodes = Mono.fromFuture(future).doOnNext(nodes -> {
            applyAuthenticationCredentials(nodes, seed);
        });

        return initialNodes.map(this::getConnections)
                .flatMap(asyncConnections -> asyncConnections.asMono(seed.getTimeout(), eventExecutors))
                .flatMap(connections -> {

                    Requests requests = connections.requestPing();

                    CompletionStage> nodes = requests.getOrTimeout(seed.getTimeout(),
                            eventExecutors);

                    return Mono.fromCompletionStage(nodes).flatMap(it -> ResumeAfter.close(connections).thenEmit(it));
                });
    }

    /*
     * Establish connections asynchronously.
     */
    private AsyncConnections getConnections(Iterable nodes) {

        List nodeList = LettuceLists.newList(nodes);
        AsyncConnections connections = new AsyncConnections(nodeList);

        for (RedisNodeDescription node : nodeList) {

            RedisURI redisURI = node.getUri();
            String message = String.format("Unable to connect to %s", redisURI);
            try {
                CompletableFuture> connectionFuture = nodeConnectionFactory
                        .connectToNodeAsync(CODEC, redisURI);

                CompletableFuture> sync = new CompletableFuture<>();

                connectionFuture.whenComplete((connection, throwable) -> {

                    if (throwable != null) {

                        if (throwable instanceof RedisConnectionException) {
                            if (logger.isDebugEnabled()) {
                                logger.debug(throwable.getMessage(), throwable);
                            } else {
                                logger.warn(throwable.getMessage());
                            }
                        } else {
                            logger.warn(message, throwable);
                        }

                        sync.completeExceptionally(new RedisConnectionException(message, throwable));
                    } else {
                        connection.async().clientSetname("lettuce#MasterReplicaTopologyRefresh");
                        sync.complete(connection);
                    }
                });

                connections.addConnection(redisURI, sync);
            } catch (RuntimeException e) {
                logger.warn(String.format(message, redisURI), e);
            }
        }

        return connections;
    }

    private static void applyAuthenticationCredentials(List nodes, RedisURI seed) {

        for (RedisNodeDescription node : nodes) {
            node.getUri().applyAuthentication(seed);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy