Search in sources :

Example 1 with AVAILABLE

use of io.servicetalk.client.api.ServiceDiscovererEvent.Status.AVAILABLE in project servicetalk by apple.

the class RoundRobinLoadBalancer method selectConnection0.

private Single<C> selectConnection0(Predicate<C> selector) {
    final List<Host<ResolvedAddress, C>> usedHosts = this.usedHosts;
    if (usedHosts.isEmpty()) {
        return usedHosts == CLOSED_LIST ? failedLBClosed(targetResource) : // This is the case when SD has emitted some items but none of the hosts are available.
        failed(StacklessNoAvailableHostException.newInstance("No hosts are available to connect for " + targetResource + ".", RoundRobinLoadBalancer.class, "selectConnection0(...)"));
    }
    // try one loop over hosts and if all are expired, give up
    final int cursor = (indexUpdater.getAndIncrement(this) & Integer.MAX_VALUE) % usedHosts.size();
    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
    Host<ResolvedAddress, C> pickedHost = null;
    for (int i = 0; i < usedHosts.size(); ++i) {
        // for a particular iteration we maintain a local cursor without contention with other requests
        int localCursor = (cursor + i) % usedHosts.size();
        final Host<ResolvedAddress, C> host = usedHosts.get(localCursor);
        assert host != null : "Host can't be null.";
        // Try first to see if an existing connection can be used
        final Object[] connections = host.connState.connections;
        // With small enough search space, attempt all connections.
        // Back off after exploring most of the search space, it gives diminishing returns.
        final int attempts = connections.length < MIN_SEARCH_SPACE ? connections.length : (int) (connections.length * SEARCH_FACTOR);
        for (int j = 0; j < attempts; ++j) {
            @SuppressWarnings("unchecked") final C connection = (C) connections[rnd.nextInt(connections.length)];
            if (selector.test(connection)) {
                return succeeded(connection);
            }
        }
        // Unhealthy hosts have no open connections – that's why we don't fail earlier, the loop will not progress.
        if (host.isActiveAndHealthy()) {
            pickedHost = host;
            break;
        }
    }
    if (pickedHost == null) {
        return failed(StacklessNoAvailableHostException.newInstance("Failed to pick an active host for " + targetResource + ". Either all are busy, expired, or unhealthy: " + usedHosts, RoundRobinLoadBalancer.class, "selectConnection0(...)"));
    }
    // No connection was selected: create a new one.
    final Host<ResolvedAddress, C> host = pickedHost;
    // This LB implementation does not automatically provide TransportObserver. Therefore, we pass "null" here.
    // Users can apply a ConnectionFactoryFilter if they need to override this "null" value with TransportObserver.
    Single<? extends C> establishConnection = connectionFactory.newConnection(host.address, null);
    if (host.healthCheckConfig != null) {
        // Schedule health check before returning
        establishConnection = establishConnection.beforeOnError(t -> host.markUnhealthy(t, connectionFactory));
    }
    return establishConnection.flatMap(newCnx -> {
        // used concurrently and hence a new connection can be rejected by the selector.
        if (!selector.test(newCnx)) {
            // with the fact that select failure does not close a connection.
            return newCnx.closeAsync().concat(failed(StacklessConnectionRejectedException.newInstance("Newly created connection " + newCnx + " for " + targetResource + " was rejected by the selection filter.", RoundRobinLoadBalancer.class, "selectConnection0(...)")));
        }
        if (host.addConnection(newCnx)) {
            return succeeded(newCnx);
        }
        return newCnx.closeAsync().concat(this.usedHosts == CLOSED_LIST ? failedLBClosed(targetResource) : failed(StacklessConnectionRejectedException.newInstance("Failed to add newly created connection " + newCnx + " for " + targetResource + " for " + host, RoundRobinLoadBalancer.class, "selectConnection0(...)")));
    });
}
Also used : Arrays(java.util.Arrays) LoggerFactory(org.slf4j.LoggerFactory) LoadBalancer(io.servicetalk.client.api.LoadBalancer) ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) Integer.toHexString(java.lang.Integer.toHexString) Collections.singletonList(java.util.Collections.singletonList) SourceAdapters.fromSource(io.servicetalk.concurrent.api.SourceAdapters.fromSource) UNAVAILABLE(io.servicetalk.client.api.ServiceDiscovererEvent.Status.UNAVAILABLE) Duration(java.time.Duration) Executor(io.servicetalk.concurrent.api.Executor) AtomicReferenceFieldUpdater.newUpdater(java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater) LOAD_BALANCER_NOT_READY_EVENT(io.servicetalk.client.api.LoadBalancerReadyEvent.LOAD_BALANCER_NOT_READY_EVENT) EXPIRED(io.servicetalk.client.api.ServiceDiscovererEvent.Status.EXPIRED) AtomicReferenceFieldUpdater(java.util.concurrent.atomic.AtomicReferenceFieldUpdater) Predicate(java.util.function.Predicate) Collections.emptyList(java.util.Collections.emptyList) Collection(java.util.Collection) CompositeCloseable(io.servicetalk.concurrent.api.CompositeCloseable) AsyncCloseables.newCompositeCloseable(io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable) List(java.util.List) Stream(java.util.stream.Stream) ConnectionRejectedException(io.servicetalk.client.api.ConnectionRejectedException) Entry(java.util.Map.Entry) AtomicIntegerFieldUpdater(java.util.concurrent.atomic.AtomicIntegerFieldUpdater) Publisher(io.servicetalk.concurrent.api.Publisher) Processor(io.servicetalk.concurrent.PublisherSource.Processor) SimpleImmutableEntry(java.util.AbstractMap.SimpleImmutableEntry) Function(java.util.function.Function) Subscriber(io.servicetalk.concurrent.PublisherSource.Subscriber) ArrayList(java.util.ArrayList) AVAILABLE(io.servicetalk.client.api.ServiceDiscovererEvent.Status.AVAILABLE) Single.succeeded(io.servicetalk.concurrent.api.Single.succeeded) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom) Objects.requireNonNull(java.util.Objects.requireNonNull) DelayedCancellable(io.servicetalk.concurrent.internal.DelayedCancellable) AsyncCloseable(io.servicetalk.concurrent.api.AsyncCloseable) Publisher.from(io.servicetalk.concurrent.api.Publisher.from) AtomicIntegerFieldUpdater.newUpdater(java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater) Nullable(javax.annotation.Nullable) ConnectionFactory(io.servicetalk.client.api.ConnectionFactory) Processors.newPublisherProcessorDropHeadOnOverflow(io.servicetalk.concurrent.api.Processors.newPublisherProcessorDropHeadOnOverflow) Logger(org.slf4j.Logger) RetryStrategies.retryWithConstantBackoffFullJitter(io.servicetalk.concurrent.api.RetryStrategies.retryWithConstantBackoffFullJitter) ListenableAsyncCloseable(io.servicetalk.concurrent.api.ListenableAsyncCloseable) Single.defer(io.servicetalk.concurrent.api.Single.defer) FlowControlUtils.addWithOverflowProtection(io.servicetalk.concurrent.internal.FlowControlUtils.addWithOverflowProtection) LoadBalancedConnection(io.servicetalk.client.api.LoadBalancedConnection) Single(io.servicetalk.concurrent.api.Single) Completable(io.servicetalk.concurrent.api.Completable) LOAD_BALANCER_READY_EVENT(io.servicetalk.client.api.LoadBalancerReadyEvent.LOAD_BALANCER_READY_EVENT) NoAvailableHostException(io.servicetalk.client.api.NoAvailableHostException) AsyncCloseables.toAsyncCloseable(io.servicetalk.concurrent.api.AsyncCloseables.toAsyncCloseable) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) SourceAdapters.toSource(io.servicetalk.concurrent.api.SourceAdapters.toSource) ThrowableUtils(io.servicetalk.concurrent.internal.ThrowableUtils) Collectors.toList(java.util.stream.Collectors.toList) Completable.completed(io.servicetalk.concurrent.api.Completable.completed) Single.failed(io.servicetalk.concurrent.api.Single.failed) SequentialCancellable(io.servicetalk.concurrent.internal.SequentialCancellable) ThreadLocalRandom(java.util.concurrent.ThreadLocalRandom)

Aggregations

ConnectionFactory (io.servicetalk.client.api.ConnectionFactory)1 ConnectionRejectedException (io.servicetalk.client.api.ConnectionRejectedException)1 LoadBalancedConnection (io.servicetalk.client.api.LoadBalancedConnection)1 LoadBalancer (io.servicetalk.client.api.LoadBalancer)1 LOAD_BALANCER_NOT_READY_EVENT (io.servicetalk.client.api.LoadBalancerReadyEvent.LOAD_BALANCER_NOT_READY_EVENT)1 LOAD_BALANCER_READY_EVENT (io.servicetalk.client.api.LoadBalancerReadyEvent.LOAD_BALANCER_READY_EVENT)1 NoAvailableHostException (io.servicetalk.client.api.NoAvailableHostException)1 ServiceDiscovererEvent (io.servicetalk.client.api.ServiceDiscovererEvent)1 AVAILABLE (io.servicetalk.client.api.ServiceDiscovererEvent.Status.AVAILABLE)1 EXPIRED (io.servicetalk.client.api.ServiceDiscovererEvent.Status.EXPIRED)1 UNAVAILABLE (io.servicetalk.client.api.ServiceDiscovererEvent.Status.UNAVAILABLE)1 Processor (io.servicetalk.concurrent.PublisherSource.Processor)1 Subscriber (io.servicetalk.concurrent.PublisherSource.Subscriber)1 Subscription (io.servicetalk.concurrent.PublisherSource.Subscription)1 AsyncCloseable (io.servicetalk.concurrent.api.AsyncCloseable)1 AsyncCloseables.newCompositeCloseable (io.servicetalk.concurrent.api.AsyncCloseables.newCompositeCloseable)1 AsyncCloseables.toAsyncCloseable (io.servicetalk.concurrent.api.AsyncCloseables.toAsyncCloseable)1 Completable (io.servicetalk.concurrent.api.Completable)1 Completable.completed (io.servicetalk.concurrent.api.Completable.completed)1 CompositeCloseable (io.servicetalk.concurrent.api.CompositeCloseable)1