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

reactivefeign.cloud2.CloudReactiveFeign Maven / Gradle / Ivy

Go to download

Adds support of Spring Cloud Loadbalancer instead of Ribbon and Resilience4j instead of Hystrix

There is a newer version: 2.0.31
Show newest version
package reactivefeign.cloud2;

import feign.Contract;
import feign.MethodMetadata;
import feign.Target;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
import reactivefeign.FallbackFactory;
import reactivefeign.ReactiveFeignBuilder;
import reactivefeign.ReactiveOptions;
import reactivefeign.client.ReactiveHttpExchangeFilterFunction;
import reactivefeign.client.ReactiveHttpRequestInterceptor;
import reactivefeign.client.ReactiveHttpResponseMapper;
import reactivefeign.client.log.ReactiveLoggerListener;
import reactivefeign.client.statushandler.ReactiveStatusHandler;
import reactivefeign.cloud2.methodhandler.CircuitBreakerMethodHandlerFactory;
import reactivefeign.cloud2.publisher.LoadBalancerPublisherClient;
import reactivefeign.methodhandler.MethodHandlerFactory;
import reactivefeign.publisher.PublisherClientFactory;
import reactivefeign.publisher.PublisherHttpClient;
import reactivefeign.retry.ReactiveRetryPolicy;

import java.util.function.Function;

import static reactivefeign.ReactiveFeign.Builder.retry;

/**
 * Allows to specify load balancer {@link ReactiveLoadBalancer.Factory}
 * and ReactiveCircuitBreakerFactory with fallback factory.
 *
 * @author Sergii Karpenko
 */
public class CloudReactiveFeign {

    private static final Logger logger = LoggerFactory.getLogger(CloudReactiveFeign.class);

    public static  Builder builder(ReactiveFeignBuilder builder) {
        return new Builder<>(builder);
    }

    public static class Builder implements ReactiveFeignBuilder {

        private ReactiveFeignBuilder builder;
        private ReactiveFeignCircuitBreakerFactory circuitBreakerFactory;
        private FallbackFactory fallbackFactory;
        private ReactiveLoadBalancer.Factory loadBalancerFactory;
        private ReactiveRetryPolicy retryOnNextPolicy;

        protected Builder(ReactiveFeignBuilder builder) {
            this.builder = builder;
        }

        public Builder enableCircuitBreaker(ReactiveFeignCircuitBreakerFactory circuitBreakerFactory) {
            this.circuitBreakerFactory = circuitBreakerFactory;
            return this;
        }

        public Builder enableLoadBalancer(
                ReactiveLoadBalancer.Factory loadBalancerFactory){
            this.loadBalancerFactory = loadBalancerFactory;
            return this;
        }

        public Builder retryOnSame(ReactiveRetryPolicy retryOnSamePolicy){
            if(this.loadBalancerFactory == null){
                throw new IllegalArgumentException("loadBalancerFactory should be specified");
            }
            retryWhen(retryOnSamePolicy);
            return this;
        }

        public Builder retryOnNext(ReactiveRetryPolicy retryOnNextPolicy){
            if(this.loadBalancerFactory == null){
                throw new IllegalArgumentException("loadBalancerFactory should be specified");
            }
            this.retryOnNextPolicy = retryOnNextPolicy;
            return this;
        }

        @Override
        public Builder fallback(T fallback) {
            return fallbackFactory(throwable -> fallback);
        }

        @Override
        public Builder fallbackFactory(FallbackFactory fallbackFactory) {
            this.fallbackFactory = fallbackFactory;
            return this;
        }

        @Override
        public Builder contract(Contract contract) {
            builder = builder.contract(contract);
            return this;
        }

        @Override
        public ReactiveFeignBuilder addExchangeFilterFunction(ReactiveHttpExchangeFilterFunction exchangeFilterFunction) {
            builder = builder.addExchangeFilterFunction(exchangeFilterFunction);
            return this;
        }

        @Override
        public Builder options(ReactiveOptions options) {
            builder = builder.options(options);
            return this;
        }

        @Override
        public Builder addRequestInterceptor(ReactiveHttpRequestInterceptor requestInterceptor) {
            builder = builder.addRequestInterceptor(requestInterceptor);
            return this;
        }

        @Override
        public Builder addLoggerListener(ReactiveLoggerListener loggerListener) {
            builder = builder.addLoggerListener(loggerListener);
            return this;
        }

        @Override
        public Builder decode404() {
            builder = builder.decode404();
            return this;
        }

        @Override
        public Builder statusHandler(ReactiveStatusHandler statusHandler) {
            builder = builder.statusHandler(statusHandler);
            return this;
        }

        @Override
        public Builder responseMapper(ReactiveHttpResponseMapper responseMapper) {
            builder =  builder.responseMapper(responseMapper);
            return this;
        }

        @Override
        public Builder retryWhen(ReactiveRetryPolicy retryPolicy) {
            builder =  builder.retryWhen(retryPolicy);
            return this;
        }

        @Override
        public Contract contract() {
            return builder.contract();
        }

        @Override
        public MethodHandlerFactory buildReactiveMethodHandlerFactory(PublisherClientFactory reactiveClientFactory) {
            if(circuitBreakerFactory == null){
                builder.fallbackFactory(fallbackFactory);
                return builder.buildReactiveMethodHandlerFactory(reactiveClientFactory);
            } else {
                return new CircuitBreakerMethodHandlerFactory(
                        builder.buildReactiveMethodHandlerFactory(reactiveClientFactory),
                        circuitBreakerFactory,
                        (Function) fallbackFactory);
            }
        }

        @Override
        public PublisherClientFactory buildReactiveClientFactory() {
            PublisherClientFactory publisherClientFactory = builder.buildReactiveClientFactory();
            return new PublisherClientFactory(){

                private Target target;

                @Override
                public void target(Target target) {
                    this.target = target;
                    publisherClientFactory.target(target);
                }

                @Override
                public PublisherHttpClient create(MethodMetadata methodMetadata) {
                    PublisherHttpClient publisherClient = publisherClientFactory.create(methodMetadata);
                    if(!target.name().equals(target.url()) && loadBalancerFactory != null){
                        publisherClient = new LoadBalancerPublisherClient(
                                loadBalancerFactory.getInstance(target.name()), publisherClient);
                        if(retryOnNextPolicy != null){
                            publisherClient = retry(publisherClient, methodMetadata, retryOnNextPolicy.toRetryFunction());
                        }
                        return publisherClient;
                    } else {
                        if(retryOnNextPolicy != null){
                            logger.warn("retryOnNextPolicy will be ignored " +
                                    "as loadBalancerFactory is not configured for {} reactive feign client", target.name());
                        }
                        return publisherClient;
                    }

                }
            };
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy