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

com.palantir.dialogue.clients.DialogueClients Maven / Gradle / Ivy

The newest version!
/*
 * (c) Copyright 2020 Palantir Technologies Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.palantir.dialogue.clients;

import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CheckReturnValue;
import com.palantir.conjure.java.api.config.service.ServicesConfigBlock;
import com.palantir.conjure.java.client.config.ClientConfiguration;
import com.palantir.conjure.java.clients.ConjureClients;
import com.palantir.conjure.java.clients.ConjureClients.WithClientOptions;
import com.palantir.dialogue.Channel;
import com.palantir.dialogue.ConjureRuntime;
import com.palantir.dialogue.core.DialogueChannel;
import com.palantir.dialogue.core.DialogueDnsResolver;
import com.palantir.refreshable.Refreshable;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;

/**
 * The {@link ReloadingFactory} abstraction allows users to declaratively construct clients for any of the services
 * named in the given {@link ServicesConfigBlock}. Client behaviour can be customized using the fluent methods from
 * {@link WithClientOptions} or {@link WithDialogueOptions}. Users may also choose to create one-off non-live reloading
 * clients.
 *
 * For maximum performance, we take great care to re-use underlying Apache connection pools as this avoids unnecessary
 * TLS handshakes. To achieve this, it is recommended to call {@link ReloadingFactory#create} once for the lifetime of
 * a JVM. There is no need to manually close clients or connection pools, this will be done automatically.
 *
 * Libraries may depend on interfaces contained in this class and/or interfaces from conjure-java-runtime's
 * {@link ConjureClients}. All other classes in this package are considered package-private implementation details
 * and are subject to change.
 */
public final class DialogueClients {

    public static ReloadingFactory create(Refreshable scb) {
        return new ReloadingClientFactory(
                ImmutableReloadingParams.builder().scb(scb).build(), ChannelCache.createEmptyCache());
    }

    /**
     * Prefer {@link #create(Refreshable)}. Using a configured {@link ReloadingFactory} should always be preferred
     * over this method, it only exists to ease migration.
     *
     * Construct an instance of the given {@code clientInterface} which can be used to make network calls to the
     * single conceptual upstream identified by {@code clientConfiguration}.
     *
     * Behaviour is undefined if {@code clientConfiguration} contains no URIs.
     *
     * @param clientInterface Dialogue client interface annotated with {@link com.palantir.dialogue.DialogueService}
     * @param clientConfiguration Configuration which must contain a user-agent
     */
    public static  T create(Class clientInterface, ClientConfiguration clientConfiguration) {
        return LegacyConstruction.getNonReloading(clientInterface, clientConfiguration);
    }

    /** Parameters necessary for {@link DialogueChannel#builder()} and constructing an actual BlockingFoo instance. */
    @CheckReturnValue
    public interface WithDialogueOptions {
        T withRuntime(ConjureRuntime runtime);

        /**
         * The Apache http client uses blocking socket operations, so threads from this executor will be used to wait
         * for responses. It's strongly recommended that custom executors support tracing-java. Cached executors are
         * the best fit because we use concurrency limiters to bound concurrent requests.
         */
        T withBlockingExecutor(ExecutorService blockingExecutor);
    }

    /** Low-level API. Most users won't need this, but it is necessary to construct feign-shim clients. */
    public interface ReloadingChannelFactory {
        Channel getChannel(String serviceName);
    }

    public interface NonReloadingChannelFactory {
        /**
         * Low level API.
         *
         * @deprecated should not be used going forward, prefer reloadable factories.
         */
        @Deprecated
        Channel getNonReloadingChannel(String channelName, ClientConfiguration clientConfiguration);
    }

    public interface ClientConfigurationNonReloadingClientFactory {
        /**
         * Construct an instance of the given {@code clientInterface} which can be used to make network calls to the
         * single conceptual upstream identified by {@code clientConfiguration}.
         *
         * Behaviour is undefined if {@code clientConfiguration} contains no URIs.
         *
         * @deprecated should not be used going forward, prefer reloadable factories.
         */
        @Deprecated
         T getNonReloading(Class clientInterface, ClientConfiguration clientConfiguration);
    }

    /** A stateful object - should only need one of these. Live reloads under the hood. */
    public interface StickyChannelFactory {
        /**
         * Returns a channel which will route all requests to a single host, even if that host returns some 429s.
         * Each successive call to this method may get a different channel (or it may return the same one).
         */
        Channel getStickyChannel();

         T getCurrentBest(Class clientInterface);
    }

    /** A stateful object - should only need one of these. Live reloads under the hood. */
    @Beta
    public interface StickyChannelFactory2 {
        /**
         * Returns a channel which will route all requests to a single host, even if that host returns some 429s.
         * Each successive call to this method may get a different channel (or it may return the same one).
         */
        Channel getStickyChannel();

         T sticky(Class clientInterface);

        /**
         * Creates a new {@link StickyChannelSession} which can be used to create multiple
         * clients bound to the same session.
         */
        StickyChannelSession session();
    }

    /**
     * Represents a single session of {@link StickyChannelFactory2} where the underlying channel will not change.
     * This is useful when multiple client interfaces must be bound to use the same host.
     */
    public interface StickyChannelSession {
        /**
         * Returns a channel which will route all requests to a single host, even if that host returns some 429s.
         * Each successive call to this method may get a different channel (or it may return the same one).
         */
        Channel getStickyChannel();

         T sticky(Class clientInterface);
    }

    public interface PerHostClientFactory {

        /**
         * Returns a list of channels where each channel will route requests to a single, unique host, even if that host
         * returns some 429s.
         */
        default Refreshable> getPerHostChannels() {
            return getNamedPerHostChannels().map(channels -> ImmutableList.copyOf(channels.values()));
        }

        default  Refreshable> getPerHost(Class clientInterface) {
            return getNamedPerHost(clientInterface).map(channels -> ImmutableList.copyOf(channels.values()));
        }

        /**
         * Returns a list of channels where each channel will route requests to a single, unique host, even if that host
         * returns some 429s. The channels are uniquely identified by a stable, opaque key.
         */
        Refreshable> getNamedPerHostChannels();

         Refreshable> getNamedPerHost(Class clientInterface);
    }

    public interface ReloadingFactory
            extends ConjureClients.ReloadingClientFactory,
                    WithClientOptions,
                    WithDialogueOptions,
                    ConjureClients.NonReloadingClientFactory,
                    ConjureClients.ToReloadingFactory,
                    ReloadingChannelFactory,
                    NonReloadingChannelFactory,
                    ClientConfigurationNonReloadingClientFactory {

        /**
         * Configures the {@link DialogueDnsResolver} used by clients managed by this factory.
         * This should generally only be used for tests.
         */
        ReloadingFactory withDnsResolver(DialogueDnsResolver dnsResolver);

        /**
         * Configures the interval at which the {@link DialogueDnsResolver} is polled for DNS updates.
         * This should generally only be used for tests.
         */
        ReloadingFactory withDnsRefreshInterval(Duration interval);

        /** Feature flag to opt into or out of the default dns-based node discovery behavior. */
        ReloadingFactory withDnsNodeDiscovery(boolean dnsNodeDiscovery);

        StickyChannelFactory getStickyChannels(String serviceName);

        @Beta
        StickyChannelFactory2 getStickyChannels2(String serviceName);

        PerHostClientFactory perHost(String serviceName);
    }

    private DialogueClients() {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy