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

io.lettuce.core.masterreplica.StaticMasterReplicaTopologyProvider 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.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

import reactor.core.publisher.Flux;
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.codec.StringCodec;
import io.lettuce.core.internal.Exceptions;
import io.lettuce.core.internal.LettuceAssert;
import io.lettuce.core.models.role.RedisNodeDescription;
import io.lettuce.core.models.role.RoleParser;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * Topology provider for a static node collection. This provider uses a static collection of nodes to determine the role of each
 * {@link RedisURI node}. Node roles may change during runtime but the configuration must remain the same. This
 * {@link TopologyProvider} does not auto-discover nodes.
 *
 * @author Mark Paluch
 * @author Adam McElwee
 */
class StaticMasterReplicaTopologyProvider implements TopologyProvider {

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

    private final RedisClient redisClient;

    private final Iterable redisURIs;

    public StaticMasterReplicaTopologyProvider(RedisClient redisClient, Iterable redisURIs) {

        LettuceAssert.notNull(redisClient, "RedisClient must not be null");
        LettuceAssert.notNull(redisURIs, "RedisURIs must not be null");
        LettuceAssert.notNull(redisURIs.iterator().hasNext(), "RedisURIs must not be empty");

        this.redisClient = redisClient;
        this.redisURIs = redisURIs;
    }

    @Override
    @SuppressWarnings("rawtypes")
    public List getNodes() {

        RedisURI next = redisURIs.iterator().next();

        try {
            return getNodesAsync().get(next.getTimeout().toMillis(), TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            throw Exceptions.bubble(e);
        }
    }

    @Override
    public CompletableFuture> getNodesAsync() {

        List> connections = new CopyOnWriteArrayList<>();

        Flux uris = Flux.fromIterable(redisURIs);
        Mono> nodes = uris.flatMap(uri -> getNodeDescription(connections, uri)).collectList()
                .flatMap((nodeDescriptions) -> {

                    if (nodeDescriptions.isEmpty()) {
                        return Mono.error(new RedisConnectionException(
                                String.format("Failed to connect to at least one node in %s", redisURIs)));
                    }

                    return Mono.just(nodeDescriptions);
                });

        return nodes.toFuture();
    }

    private Mono getNodeDescription(List> connections,
            RedisURI uri) {

        return Mono.fromCompletionStage(redisClient.connectAsync(StringCodec.UTF8, uri)) //
                .onErrorResume(t -> {

                    logger.warn("Cannot connect to {}", uri, t);
                    return Mono.empty();
                }) //
                .doOnNext(connections::add) //
                .flatMap(connection -> {

                    Mono instance = getNodeDescription(uri, connection);

                    return instance.flatMap(it -> ResumeAfter.close(connection).thenEmit(it)).doFinally(s -> {
                        connections.remove(connection);
                    });
                });
    }

    private static Mono getNodeDescription(RedisURI uri,
            StatefulRedisConnection connection) {

        return connection.reactive().role().collectList().map(RoleParser::parse)
                .map(it -> new RedisMasterReplicaNode(uri.getHost(), uri.getPort(), uri, it.getRole()));
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy