mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	changes to create load balancers and qos providers on first request to reroute and then check if they have changed on subsequent requests but not create again if they havent..quite a few breaking changes here.
This commit is contained in:
		@@ -149,7 +149,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
        public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
 | 
			
		||||
        public ReRouteBuilder WithReRouteKey(string loadBalancerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerKey = loadBalancerKey;
 | 
			
		||||
            return this;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,16 +2,9 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfigurationBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private string _serviceDiscoveryProvider;
 | 
			
		||||
        private string _serviceDiscoveryProviderHost;
 | 
			
		||||
        private int _serviceDiscoveryProviderPort;
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProvider = serviceDiscoveryProvider;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfigurationBuilder WithServiceDiscoveryProviderHost(string serviceDiscoveryProviderHost)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceDiscoveryProviderHost = serviceDiscoveryProviderHost;
 | 
			
		||||
@@ -26,7 +19,7 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
 | 
			
		||||
        public ServiceProviderConfiguration Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new ServiceProviderConfiguration(_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
 | 
			
		||||
            return new ServiceProviderConfiguration(_serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,8 +26,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        private readonly IOptions<FileConfiguration> _options;
 | 
			
		||||
        private readonly IConfigurationValidator _configurationValidator;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
        private readonly IClaimsToThingCreator _claimsToThingCreator;
 | 
			
		||||
        private readonly IAuthenticationOptionsCreator _authOptionsCreator;
 | 
			
		||||
        private readonly IUpstreamTemplatePatternCreator _upstreamTemplatePatternCreator;
 | 
			
		||||
@@ -43,8 +41,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            IOptions<FileConfiguration> options, 
 | 
			
		||||
            IConfigurationValidator configurationValidator,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            IQoSProviderFactory qoSProviderFactory, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse,
 | 
			
		||||
            IClaimsToThingCreator claimsToThingCreator,
 | 
			
		||||
            IAuthenticationOptionsCreator authOptionsCreator,
 | 
			
		||||
            IUpstreamTemplatePatternCreator upstreamTemplatePatternCreator,
 | 
			
		||||
@@ -62,8 +58,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            _requestIdKeyCreator = requestIdKeyCreator;
 | 
			
		||||
            _upstreamTemplatePatternCreator = upstreamTemplatePatternCreator;
 | 
			
		||||
            _authOptionsCreator = authOptionsCreator;
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _options = options;
 | 
			
		||||
            _configurationValidator = configurationValidator;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<FileOcelotConfigurationCreator>();
 | 
			
		||||
@@ -108,7 +102,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
 | 
			
		||||
            foreach (var reRoute in fileConfiguration.ReRoutes)
 | 
			
		||||
            {
 | 
			
		||||
                var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
 | 
			
		||||
                var ocelotReRoute = SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
 | 
			
		||||
                reRoutes.Add(ocelotReRoute);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -117,7 +111,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        private ReRoute SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
        {
 | 
			
		||||
            var fileReRouteOptions = _fileReRouteOptionsCreator.Create(fileReRoute);
 | 
			
		||||
 | 
			
		||||
@@ -162,7 +156,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithLoadBalancer(fileReRoute.LoadBalancer)
 | 
			
		||||
                .WithDownstreamHost(fileReRoute.DownstreamHost)
 | 
			
		||||
                .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                .WithLoadBalancerKey(reRouteKey)
 | 
			
		||||
                .WithReRouteKey(reRouteKey)
 | 
			
		||||
                .WithIsQos(fileReRouteOptions.IsQos)
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
 | 
			
		||||
@@ -172,7 +166,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            SetupQosProvider(reRoute);
 | 
			
		||||
            return reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -182,11 +175,5 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}|{string.Join(",", fileReRoute.UpstreamHttpMethod)}";
 | 
			
		||||
            return loadBalancerKey;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SetupQosProvider(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
            _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,6 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
 | 
			
		||||
 | 
			
		||||
            return new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                    .WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
 | 
			
		||||
                    .WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
 | 
			
		||||
                    .WithServiceDiscoveryProviderPort(serviceProviderPort)
 | 
			
		||||
                    .Build();
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,6 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
{
 | 
			
		||||
    public class FileServiceDiscoveryProvider
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        public string Provider {get;set;}
 | 
			
		||||
        public string Host {get;set;}
 | 
			
		||||
        public int Port { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -11,19 +11,19 @@ namespace Ocelot.Configuration.Repository
 | 
			
		||||
    public class ConsulOcelotConfigurationRepository : IOcelotConfigurationRepository
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ConsulClient _consul;
 | 
			
		||||
        private ConsulRegistryConfiguration _configuration;
 | 
			
		||||
        private string _ocelotConfiguration = "OcelotConfiguration";
 | 
			
		||||
        private Cache.IOcelotCache<IOcelotConfiguration> _cache;
 | 
			
		||||
        private readonly Cache.IOcelotCache<IOcelotConfiguration> _cache;
 | 
			
		||||
 | 
			
		||||
        public ConsulOcelotConfigurationRepository(ConsulRegistryConfiguration consulRegistryConfiguration, Cache.IOcelotCache<IOcelotConfiguration> cache)
 | 
			
		||||
 | 
			
		||||
        public ConsulOcelotConfigurationRepository(Cache.IOcelotCache<IOcelotConfiguration> cache, ServiceProviderConfiguration serviceProviderConfig)
 | 
			
		||||
        {
 | 
			
		||||
            var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
 | 
			
		||||
            var consulPort = consulRegistryConfiguration?.Port ?? 8500;
 | 
			
		||||
            _configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName);
 | 
			
		||||
            var consulHost = string.IsNullOrEmpty(serviceProviderConfig?.ServiceProviderHost) ? "localhost" : serviceProviderConfig?.ServiceProviderHost;
 | 
			
		||||
            var consulPort = serviceProviderConfig?.ServiceProviderPort ?? 8500;
 | 
			
		||||
            var configuration = new ConsulRegistryConfiguration(consulHost, consulPort, _ocelotConfiguration);
 | 
			
		||||
            _cache = cache;
 | 
			
		||||
            _consul = new ConsulClient(config =>
 | 
			
		||||
            _consul = new ConsulClient(c =>
 | 
			
		||||
            {
 | 
			
		||||
                config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}");
 | 
			
		||||
                c.Address = new Uri($"http://{configuration.HostName}:{configuration.Port}");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,14 +2,12 @@
 | 
			
		||||
{
 | 
			
		||||
    public class ServiceProviderConfiguration
 | 
			
		||||
    {
 | 
			
		||||
        public ServiceProviderConfiguration(string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
 | 
			
		||||
        public ServiceProviderConfiguration(string serviceProviderHost, int serviceProviderPort)
 | 
			
		||||
        {
 | 
			
		||||
            ServiceDiscoveryProvider = serviceDiscoveryProvider;
 | 
			
		||||
            ServiceProviderHost = serviceProviderHost;
 | 
			
		||||
            ServiceProviderPort = serviceProviderPort;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string ServiceDiscoveryProvider { get; }
 | 
			
		||||
        public string ServiceProviderHost { get; private set; }
 | 
			
		||||
        public int ServiceProviderPort { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -45,20 +45,39 @@ using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration.Builder;
 | 
			
		||||
using FileConfigurationProvider = Ocelot.Configuration.Provider.FileConfigurationProvider;
 | 
			
		||||
using Ocelot.LoadBalancer;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    public static class ServiceCollectionExtensions
 | 
			
		||||
    {
 | 
			
		||||
        public static IServiceCollection AddOcelotStoreConfigurationInConsul(this IServiceCollection services, ConsulRegistryConfiguration consulConfig)
 | 
			
		||||
        public static IServiceCollection AddStoreOcelotConfigurationInConsul(this IServiceCollection services, IConfigurationRoot configurationRoot)
 | 
			
		||||
        {
 | 
			
		||||
            services.AddSingleton<ConsulRegistryConfiguration>(consulConfig);
 | 
			
		||||
            var serviceDiscoveryPort = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Port", 0);
 | 
			
		||||
            var serviceDiscoveryHost = configurationRoot.GetValue("GlobalConfiguration:ServiceDiscoveryProvider:Host", string.Empty);
 | 
			
		||||
 | 
			
		||||
            var config = new ServiceProviderConfigurationBuilder()
 | 
			
		||||
                .WithServiceDiscoveryProviderPort(serviceDiscoveryPort)
 | 
			
		||||
                .WithServiceDiscoveryProviderHost(serviceDiscoveryHost)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            services.AddSingleton<ServiceProviderConfiguration>(config);
 | 
			
		||||
            services.AddSingleton<IOcelotConfigurationRepository, ConsulOcelotConfigurationRepository>();
 | 
			
		||||
            return services;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddOcelot(this IServiceCollection services,
 | 
			
		||||
            IConfigurationRoot configurationRoot)
 | 
			
		||||
        {
 | 
			
		||||
            Action<ConfigurationBuilderCachePart> defaultCachingSettings = x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return services.AddOcelot(configurationRoot, defaultCachingSettings);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static IServiceCollection AddOcelot(this IServiceCollection services, IConfigurationRoot configurationRoot, Action<ConfigurationBuilderCachePart> settings)
 | 
			
		||||
        {
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,14 @@ using Ocelot.Values;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public class LeastConnectionLoadBalancer : ILoadBalancer
 | 
			
		||||
    public class LeastConnection : ILoadBalancer
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Func<Task<List<Service>>> _services;
 | 
			
		||||
        private readonly List<Lease> _leases;
 | 
			
		||||
        private readonly string _serviceName;
 | 
			
		||||
        private static readonly object _syncLock = new object();
 | 
			
		||||
 | 
			
		||||
        public LeastConnectionLoadBalancer(Func<Task<List<Service>>> services, string serviceName)
 | 
			
		||||
        public LeastConnection(Func<Task<List<Service>>> services, string serviceName)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
            _serviceName = serviceName;
 | 
			
		||||
@@ -19,9 +19,9 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
            switch (reRoute.LoadBalancer)
 | 
			
		||||
            {
 | 
			
		||||
                case "RoundRobin":
 | 
			
		||||
                    return new RoundRobinLoadBalancer(async () => await serviceProvider.Get());
 | 
			
		||||
                    return new RoundRobin(async () => await serviceProvider.Get());
 | 
			
		||||
                case "LeastConnection":
 | 
			
		||||
                    return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceName);
 | 
			
		||||
                    return new LeastConnection(async () => await serviceProvider.Get(), reRoute.ServiceName);
 | 
			
		||||
                default:
 | 
			
		||||
                    return new NoLoadBalancer(await serviceProvider.Get());
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -22,16 +22,11 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                ILoadBalancer loadBalancer;
 | 
			
		||||
 | 
			
		||||
                if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out loadBalancer))
 | 
			
		||||
                if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out var loadBalancer))
 | 
			
		||||
                {
 | 
			
		||||
                    loadBalancer = _loadBalancers[reRoute.ReRouteKey];
 | 
			
		||||
 | 
			
		||||
                    //todo - we have some duplicate namey type logic in the LoadBalancerFactory...maybe we can do something
 | 
			
		||||
                    //about this..
 | 
			
		||||
                    if((reRoute.LoadBalancer == "RoundRobin" && loadBalancer.GetType() != typeof(RoundRobinLoadBalancer))
 | 
			
		||||
                        || (reRoute.LoadBalancer == "LeastConnection" && loadBalancer.GetType() != typeof(LeastConnectionLoadBalancer)))
 | 
			
		||||
                    if(reRoute.LoadBalancer != loadBalancer.GetType().Name)
 | 
			
		||||
                    {
 | 
			
		||||
                        loadBalancer = await _factory.Get(reRoute, config);
 | 
			
		||||
                        AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
@@ -55,18 +50,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
 | 
			
		||||
        private void AddLoadBalancer(string key, ILoadBalancer loadBalancer)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => {
 | 
			
		||||
                return loadBalancer;
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // if (!_loadBalancers.ContainsKey(key))
 | 
			
		||||
            // {
 | 
			
		||||
            //     _loadBalancers.TryAdd(key, loadBalancer);
 | 
			
		||||
            // }
 | 
			
		||||
 | 
			
		||||
            // ILoadBalancer old;
 | 
			
		||||
            // _loadBalancers.Remove(key, out old);
 | 
			
		||||
            // _loadBalancers.TryAdd(key, loadBalancer);
 | 
			
		||||
            _loadBalancers.AddOrUpdate(key, loadBalancer, (x, y) => loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,13 @@ using System;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.LoadBalancers
 | 
			
		||||
{
 | 
			
		||||
    public class RoundRobinLoadBalancer : ILoadBalancer
 | 
			
		||||
    public class RoundRobin : ILoadBalancer
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Func<Task<List<Service>>> _services;
 | 
			
		||||
 | 
			
		||||
        private int _last;
 | 
			
		||||
 | 
			
		||||
        public RoundRobinLoadBalancer(Func<Task<List<Service>>> services)
 | 
			
		||||
        public RoundRobin(Func<Task<List<Service>>> services)
 | 
			
		||||
        {
 | 
			
		||||
            _services = services;
 | 
			
		||||
        }
 | 
			
		||||
@@ -32,7 +32,7 @@ namespace Ocelot.Request.Middleware
 | 
			
		||||
        {
 | 
			
		||||
            _logger.LogDebug("started calling request builder middleware");
 | 
			
		||||
 | 
			
		||||
            var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
 | 
			
		||||
            var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute);
 | 
			
		||||
 | 
			
		||||
            if (qosProvider.IsError)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								src/Ocelot/Requester/QoS/CircuitBreaker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/Ocelot/Requester/QoS/CircuitBreaker.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class CircuitBreaker
 | 
			
		||||
    {
 | 
			
		||||
        public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy)
 | 
			
		||||
        {
 | 
			
		||||
            CircuitBreakerPolicy = circuitBreakerPolicy;
 | 
			
		||||
            TimeoutPolicy = timeoutPolicy;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; }
 | 
			
		||||
        public TimeoutPolicy TimeoutPolicy { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Ocelot/Requester/QoS/IQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Ocelot/Requester/QoS/IQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public interface IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Polly;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
@@ -15,131 +7,4 @@ namespace Ocelot.Requester.QoS
 | 
			
		||||
    {
 | 
			
		||||
        IQoSProvider Get(ReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class QoSProviderFactory : IQoSProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLoggerFactory _loggerFactory;
 | 
			
		||||
 | 
			
		||||
        public QoSProviderFactory(IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _loggerFactory = loggerFactory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IQoSProvider Get(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            if (reRoute.IsQos)
 | 
			
		||||
            {
 | 
			
		||||
                return new PollyQoSProvider(reRoute, _loggerFactory);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new NoQoSProvider();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public interface IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NoQoSProvider : IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        public CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class PollyQoSProvider : IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CircuitBreakerPolicy _circuitBreakerPolicy;
 | 
			
		||||
        private readonly TimeoutPolicy _timeoutPolicy;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly CircuitBreaker _circuitBreaker;
 | 
			
		||||
 | 
			
		||||
        public PollyQoSProvider(ReRoute reRoute, IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<PollyQoSProvider>();
 | 
			
		||||
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .CircuitBreakerAsync(
 | 
			
		||||
                    exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
 | 
			
		||||
                    durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
 | 
			
		||||
                    onBreak: (ex, breakDelay) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogError(
 | 
			
		||||
                            ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
 | 
			
		||||
                    },
 | 
			
		||||
                    onReset: () =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again.");
 | 
			
		||||
                    },
 | 
			
		||||
                    onHalfOpen: () =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.");
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            _circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CircuitBreaker CircuitBreaker => _circuitBreaker;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class CircuitBreaker
 | 
			
		||||
    {
 | 
			
		||||
        public CircuitBreaker(CircuitBreakerPolicy circuitBreakerPolicy, TimeoutPolicy timeoutPolicy)
 | 
			
		||||
        {
 | 
			
		||||
            CircuitBreakerPolicy = circuitBreakerPolicy;
 | 
			
		||||
            TimeoutPolicy = timeoutPolicy;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CircuitBreakerPolicy CircuitBreakerPolicy { get; private set; }
 | 
			
		||||
        public TimeoutPolicy TimeoutPolicy { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public interface IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        Response<IQoSProvider> Get(string key);
 | 
			
		||||
        Response Add(string key, IQoSProvider loadBalancer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class QosProviderHouse : IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<string, IQoSProvider> _qoSProviders;
 | 
			
		||||
 | 
			
		||||
        public QosProviderHouse()
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProviders = new Dictionary<string, IQoSProvider>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response<IQoSProvider> Get(string key)
 | 
			
		||||
        {
 | 
			
		||||
            IQoSProvider qoSProvider;
 | 
			
		||||
 | 
			
		||||
            if (_qoSProviders.TryGetValue(key, out qoSProvider))
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<IQoSProvider>(_qoSProviders[key]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
			
		||||
            {
 | 
			
		||||
                new UnableToFindQoSProviderError($"unabe to find qos provider for {key}")
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response Add(string key, IQoSProvider loadBalancer)
 | 
			
		||||
        {
 | 
			
		||||
            if (!_qoSProviders.ContainsKey(key))
 | 
			
		||||
            {
 | 
			
		||||
                _qoSProviders.Add(key, loadBalancer);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _qoSProviders.Remove(key);
 | 
			
		||||
            _qoSProviders.Add(key, loadBalancer);
 | 
			
		||||
            return new OkResponse();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								src/Ocelot/Requester/QoS/IQosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/Ocelot/Requester/QoS/IQosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public interface IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        Response<IQoSProvider> Get(ReRoute reRoute);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Ocelot/Requester/QoS/NoQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Ocelot/Requester/QoS/NoQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class NoQoSProvider : IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        public CircuitBreaker CircuitBreaker { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/Ocelot/Requester/QoS/PollyQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Ocelot/Requester/QoS/PollyQoSProvider.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Polly;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class PollyQoSProvider : IQoSProvider
 | 
			
		||||
    {
 | 
			
		||||
        private readonly CircuitBreakerPolicy _circuitBreakerPolicy;
 | 
			
		||||
        private readonly TimeoutPolicy _timeoutPolicy;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly CircuitBreaker _circuitBreaker;
 | 
			
		||||
 | 
			
		||||
        public PollyQoSProvider(ReRoute reRoute, IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<PollyQoSProvider>();
 | 
			
		||||
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.TimeoutValue), reRoute.QosOptionsOptions.TimeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .CircuitBreakerAsync(
 | 
			
		||||
                    exceptionsAllowedBeforeBreaking: reRoute.QosOptionsOptions.ExceptionsAllowedBeforeBreaking,
 | 
			
		||||
                    durationOfBreak: TimeSpan.FromMilliseconds(reRoute.QosOptionsOptions.DurationOfBreak),
 | 
			
		||||
                    onBreak: (ex, breakDelay) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogError(
 | 
			
		||||
                            ".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
 | 
			
		||||
                    },
 | 
			
		||||
                    onReset: () =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again.");
 | 
			
		||||
                    },
 | 
			
		||||
                    onHalfOpen: () =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.");
 | 
			
		||||
                    }
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
            _circuitBreaker = new CircuitBreaker(_circuitBreakerPolicy, _timeoutPolicy);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CircuitBreaker CircuitBreaker => _circuitBreaker;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								src/Ocelot/Requester/QoS/QoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/Ocelot/Requester/QoS/QoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class QoSProviderFactory : IQoSProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLoggerFactory _loggerFactory;
 | 
			
		||||
 | 
			
		||||
        public QoSProviderFactory(IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _loggerFactory = loggerFactory;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IQoSProvider Get(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            if (reRoute.IsQos)
 | 
			
		||||
            {
 | 
			
		||||
                return new PollyQoSProvider(reRoute, _loggerFactory);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new NoQoSProvider();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								src/Ocelot/Requester/QoS/QosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/Ocelot/Requester/QoS/QosProviderHouse.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class QosProviderHouse : IQosProviderHouse
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ConcurrentDictionary<string, IQoSProvider> _qoSProviders;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
 | 
			
		||||
        public QosProviderHouse(IQoSProviderFactory qoSProviderFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qoSProviders = new ConcurrentDictionary<string, IQoSProvider>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Response<IQoSProvider> Get(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (_qoSProviders.TryGetValue(reRoute.ReRouteKey, out var qosProvider))
 | 
			
		||||
                {
 | 
			
		||||
                    if (reRoute.IsQos && qosProvider.CircuitBreaker == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
                        Add(reRoute.ReRouteKey, qosProvider);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.ReRouteKey]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                qosProvider = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
                Add(reRoute.ReRouteKey, qosProvider);
 | 
			
		||||
                return new OkResponse<IQoSProvider>(qosProvider);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                return new ErrorResponse<IQoSProvider>(new List<Ocelot.Errors.Error>()
 | 
			
		||||
                {
 | 
			
		||||
                    new UnableToFindQoSProviderError($"unabe to find qos provider for {reRoute.ReRouteKey}, exception was {ex}")
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Add(string key, IQoSProvider qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProviders.AddOrUpdate(key, qosProvider, (x, y) => qosProvider);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,14 +2,14 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    public class ConsulRegistryConfiguration
 | 
			
		||||
    {
 | 
			
		||||
        public ConsulRegistryConfiguration(string hostName, int port, string serviceName)
 | 
			
		||||
        public ConsulRegistryConfiguration(string hostName, int port, string keyOfServiceInConsul)
 | 
			
		||||
        {
 | 
			
		||||
            HostName = hostName;
 | 
			
		||||
            Port = port;
 | 
			
		||||
            ServiceName = serviceName;
 | 
			
		||||
            KeyOfServiceInConsul = keyOfServiceInConsul;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string ServiceName { get; private set; }
 | 
			
		||||
        public string KeyOfServiceInConsul { get; private set; }
 | 
			
		||||
        public string HostName { get; private set; }
 | 
			
		||||
        public int Port { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
{
 | 
			
		||||
    public class ConsulServiceDiscoveryProvider : IServiceDiscoveryProvider
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ConsulRegistryConfiguration _configuration;
 | 
			
		||||
        private readonly ConsulRegistryConfiguration _consulConfig;
 | 
			
		||||
        private readonly ConsulClient _consul;
 | 
			
		||||
        private const string VersionPrefix = "version-";
 | 
			
		||||
 | 
			
		||||
@@ -18,17 +18,17 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
        {
 | 
			
		||||
            var consulHost = string.IsNullOrEmpty(consulRegistryConfiguration?.HostName) ? "localhost" : consulRegistryConfiguration.HostName;
 | 
			
		||||
            var consulPort = consulRegistryConfiguration?.Port ?? 8500;
 | 
			
		||||
            _configuration = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.ServiceName);
 | 
			
		||||
            _consulConfig = new ConsulRegistryConfiguration(consulHost, consulPort, consulRegistryConfiguration?.KeyOfServiceInConsul);
 | 
			
		||||
 | 
			
		||||
            _consul = new ConsulClient(config =>
 | 
			
		||||
            {
 | 
			
		||||
                config.Address = new Uri($"http://{_configuration.HostName}:{_configuration.Port}");
 | 
			
		||||
                config.Address = new Uri($"http://{_consulConfig.HostName}:{_consulConfig.Port}");
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<List<Service>> Get()
 | 
			
		||||
        {
 | 
			
		||||
            var queryResult = await _consul.Health.Service(_configuration.ServiceName, string.Empty, true);
 | 
			
		||||
            var queryResult = await _consul.Health.Service(_consulConfig.KeyOfServiceInConsul, string.Empty, true);
 | 
			
		||||
 | 
			
		||||
            var services = queryResult.Response.Select(BuildService);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
        {
 | 
			
		||||
            if (reRoute.UseServiceDiscovery)
 | 
			
		||||
            {
 | 
			
		||||
                return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
 | 
			
		||||
                return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var services = new List<Service>()
 | 
			
		||||
@@ -25,9 +25,9 @@ namespace Ocelot.ServiceDiscovery
 | 
			
		||||
            return new ConfigurationServiceProvider(services);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string serviceName, string serviceProviderName, string providerHostName, int providerPort)
 | 
			
		||||
        private IServiceDiscoveryProvider GetServiceDiscoveryProvider(string keyOfServiceInConsul, string providerHostName, int providerPort)
 | 
			
		||||
        {
 | 
			
		||||
            var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, serviceName);
 | 
			
		||||
            var consulRegistryConfiguration = new ConsulRegistryConfiguration(providerHostName, providerPort, keyOfServiceInConsul);
 | 
			
		||||
            return new ConsulServiceDiscoveryProvider(consulRegistryConfiguration);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user