mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	Fixed issue where qos was being created for each request so circuit breaker was never stopping traffic going to downstream service.
This commit is contained in:
		
							
								
								
									
										34
									
								
								src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/Ocelot/Configuration/Builder/QoSOptionsBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
namespace Ocelot.Configuration.Builder
 | 
			
		||||
{
 | 
			
		||||
    public class QoSOptionsBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private int _exceptionsAllowedBeforeBreaking;
 | 
			
		||||
 | 
			
		||||
        private int _durationOfBreak;
 | 
			
		||||
 | 
			
		||||
        private int _timeoutValue;
 | 
			
		||||
 | 
			
		||||
        public QoSOptionsBuilder WithExceptionsAllowedBeforeBreaking(int exceptionsAllowedBeforeBreaking)
 | 
			
		||||
        {
 | 
			
		||||
            _exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public QoSOptionsBuilder WithDurationOfBreak(int durationOfBreak)
 | 
			
		||||
        {
 | 
			
		||||
            _durationOfBreak = durationOfBreak;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public QoSOptionsBuilder WithTimeoutValue(int timeoutValue)
 | 
			
		||||
        {
 | 
			
		||||
            _timeoutValue = timeoutValue;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public QoSOptions Build()
 | 
			
		||||
        {
 | 
			
		||||
            return new QoSOptions(_exceptionsAllowedBeforeBreaking, _durationOfBreak, _timeoutValue);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
@@ -10,9 +9,9 @@ using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.Configuration.Parser;
 | 
			
		||||
using Ocelot.Configuration.Validator;
 | 
			
		||||
using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Utilities;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.Creator
 | 
			
		||||
{
 | 
			
		||||
@@ -26,11 +25,14 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        private const string RegExMatchEverything = ".*";
 | 
			
		||||
        private const string RegExMatchEndString = "$";
 | 
			
		||||
        private const string RegExIgnoreCase = "(?i)";
 | 
			
		||||
        private const string RegExForwardSlashOnly = "^/$";
 | 
			
		||||
 | 
			
		||||
        private readonly IClaimToThingConfigurationParser _claimToThingConfigurationParser;
 | 
			
		||||
        private readonly ILogger<FileOcelotConfigurationCreator> _logger;
 | 
			
		||||
        private readonly ILoadBalancerFactory _loadBalanceFactory;
 | 
			
		||||
        private readonly ILoadBalancerHouse _loadBalancerHouse;
 | 
			
		||||
        private readonly IQoSProviderFactory _qoSProviderFactory;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
 | 
			
		||||
        public FileOcelotConfigurationCreator(
 | 
			
		||||
            IOptions<FileConfiguration> options, 
 | 
			
		||||
@@ -38,10 +40,14 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            IClaimToThingConfigurationParser claimToThingConfigurationParser, 
 | 
			
		||||
            ILogger<FileOcelotConfigurationCreator> logger,
 | 
			
		||||
            ILoadBalancerFactory loadBalancerFactory,
 | 
			
		||||
            ILoadBalancerHouse loadBalancerHouse)
 | 
			
		||||
            ILoadBalancerHouse loadBalancerHouse, 
 | 
			
		||||
            IQoSProviderFactory qoSProviderFactory, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalanceFactory = loadBalancerFactory;
 | 
			
		||||
            _loadBalancerHouse = loadBalancerHouse;
 | 
			
		||||
            _qoSProviderFactory = qoSProviderFactory;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _options = options;
 | 
			
		||||
            _configurationValidator = configurationValidator;
 | 
			
		||||
            _claimToThingConfigurationParser = claimToThingConfigurationParser;
 | 
			
		||||
@@ -86,17 +92,17 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        {
 | 
			
		||||
            var isAuthenticated = IsAuthenticated(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isAuthorised = IsAuthenticated(fileReRoute);
 | 
			
		||||
            var isAuthorised = IsAuthorised(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isCached = IsCached(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var requestIdKey = BuildRequestId(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
            var loadBalancerKey = BuildLoadBalancerKey(fileReRoute);
 | 
			
		||||
            var reRouteKey = BuildReRouteKey(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var upstreamTemplatePattern = BuildUpstreamTemplate(fileReRoute);
 | 
			
		||||
            var upstreamTemplatePattern = BuildUpstreamTemplatePattern(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var isQos = fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions.TimeoutValue >0;
 | 
			
		||||
            var isQos = IsQoS(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
@@ -108,6 +114,8 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
 | 
			
		||||
            var claimsToQueries = BuildAddThingsToRequest(fileReRoute.AddQueriesToRequest);
 | 
			
		||||
 | 
			
		||||
            var qosOptions = BuildQoSOptions(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var reRoute = new ReRouteBuilder()
 | 
			
		||||
                .WithDownstreamPathTemplate(fileReRoute.DownstreamPathTemplate)
 | 
			
		||||
                .WithUpstreamPathTemplate(fileReRoute.UpstreamPathTemplate)
 | 
			
		||||
@@ -127,16 +135,31 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                .WithLoadBalancer(fileReRoute.LoadBalancer)
 | 
			
		||||
                .WithDownstreamHost(fileReRoute.DownstreamHost)
 | 
			
		||||
                .WithDownstreamPort(fileReRoute.DownstreamPort)
 | 
			
		||||
                .WithLoadBalancerKey(loadBalancerKey)
 | 
			
		||||
                .WithLoadBalancerKey(reRouteKey)
 | 
			
		||||
                .WithServiceProviderConfiguraion(serviceProviderConfiguration)
 | 
			
		||||
                .WithIsQos(isQos)
 | 
			
		||||
                .WithQosOptions(new QoSOptions(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking, fileReRoute.QoSOptions.DurationOfBreak, fileReRoute.QoSOptions.TimeoutValue))
 | 
			
		||||
                .WithQosOptions(qosOptions)
 | 
			
		||||
                .Build();   
 | 
			
		||||
 | 
			
		||||
            await SetupLoadBalancer(reRoute);
 | 
			
		||||
            SetupQosProvider(reRoute);
 | 
			
		||||
            return reRoute;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private QoSOptions BuildQoSOptions(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return new QoSOptionsBuilder()
 | 
			
		||||
                .WithExceptionsAllowedBeforeBreaking(fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking)
 | 
			
		||||
                .WithDurationOfBreak(fileReRoute.QoSOptions.DurationOfBreak)
 | 
			
		||||
                .WithTimeoutValue(fileReRoute.QoSOptions.TimeoutValue)
 | 
			
		||||
                .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsQoS(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.QoSOptions?.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions?.TimeoutValue > 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private bool IsAuthenticated(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider);
 | 
			
		||||
@@ -163,7 +186,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                return requestIdKey;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string BuildLoadBalancerKey(FileReRoute fileReRoute)
 | 
			
		||||
        private string BuildReRouteKey(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            //note - not sure if this is the correct key, but this is probably the only unique key i can think of given my poor brain
 | 
			
		||||
            var loadBalancerKey = $"{fileReRoute.UpstreamPathTemplate}{fileReRoute.UpstreamHttpMethod}";
 | 
			
		||||
@@ -185,7 +208,13 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        private async Task SetupLoadBalancer(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = await _loadBalanceFactory.Get(reRoute);
 | 
			
		||||
            _loadBalancerHouse.Add(reRoute.LoadBalancerKey, loadBalancer);
 | 
			
		||||
            _loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void SetupQosProvider(ReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var loadBalancer = _qoSProviderFactory.Get(reRoute);
 | 
			
		||||
            _qosProviderHouse.Add(reRoute.ReRouteKey, loadBalancer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ServiceProviderConfiguraion BuildServiceProviderConfiguration(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
 | 
			
		||||
@@ -206,7 +235,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                    .Build();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string BuildUpstreamTemplate(FileReRoute reRoute)
 | 
			
		||||
        private string BuildUpstreamTemplatePattern(FileReRoute reRoute)
 | 
			
		||||
        {
 | 
			
		||||
            var upstreamTemplate = reRoute.UpstreamPathTemplate;
 | 
			
		||||
 | 
			
		||||
@@ -230,6 +259,11 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
                upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (upstreamTemplate == "/")
 | 
			
		||||
            {
 | 
			
		||||
                return RegExForwardSlashOnly;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var route = reRoute.ReRouteIsCaseSensitive 
 | 
			
		||||
                ? $"{upstreamTemplate}{RegExMatchEndString}" 
 | 
			
		||||
                : $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,5 @@
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,12 @@ namespace Ocelot.Configuration
 | 
			
		||||
            string loadBalancer, 
 | 
			
		||||
            string downstreamHost, 
 | 
			
		||||
            int downstreamPort, 
 | 
			
		||||
            string loadBalancerKey, 
 | 
			
		||||
            string reRouteKey, 
 | 
			
		||||
            ServiceProviderConfiguraion serviceProviderConfiguraion,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos)
 | 
			
		||||
        {
 | 
			
		||||
            LoadBalancerKey = loadBalancerKey;
 | 
			
		||||
            ReRouteKey = reRouteKey;
 | 
			
		||||
            ServiceProviderConfiguraion = serviceProviderConfiguraion;
 | 
			
		||||
            LoadBalancer = loadBalancer;
 | 
			
		||||
            DownstreamHost = downstreamHost;
 | 
			
		||||
@@ -57,7 +57,7 @@ namespace Ocelot.Configuration
 | 
			
		||||
            QosOptions = qos;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string LoadBalancerKey {get;private set;}
 | 
			
		||||
        public string ReRouteKey {get;private set;}
 | 
			
		||||
        public PathTemplate DownstreamPathTemplate { get; private set; }
 | 
			
		||||
        public PathTemplate UpstreamPathTemplate { get; private set; }
 | 
			
		||||
        public string UpstreamTemplatePattern { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ using Ocelot.Logging;
 | 
			
		||||
using Ocelot.QueryStrings;
 | 
			
		||||
using Ocelot.Request.Builder;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Ocelot.Responder;
 | 
			
		||||
using Ocelot.ServiceDiscovery;
 | 
			
		||||
 | 
			
		||||
@@ -61,6 +62,8 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
        {
 | 
			
		||||
            services.AddMvcCore().AddJsonFormatters();
 | 
			
		||||
            services.AddLogging();
 | 
			
		||||
            services.AddSingleton<IQosProviderHouse, QosProviderHouse>();
 | 
			
		||||
            services.AddSingleton<IQoSProviderFactory, QoSProviderFactory>();
 | 
			
		||||
            services.AddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
 | 
			
		||||
            services.AddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
 | 
			
		||||
            services.AddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,13 @@ namespace Ocelot.DownstreamRouteFinder.Finder
 | 
			
		||||
 | 
			
		||||
            foreach (var reRoute in applicableReRoutes)
 | 
			
		||||
            {
 | 
			
		||||
                if (upstreamUrlPath == reRoute.UpstreamTemplatePattern)
 | 
			
		||||
                {
 | 
			
		||||
                    var templateVariableNameAndValues = _urlPathPlaceholderNameAndValueFinder.Find(upstreamUrlPath, reRoute.UpstreamPathTemplate.Value);
 | 
			
		||||
 | 
			
		||||
                    return new OkResponse<DownstreamRoute>(new DownstreamRoute(templateVariableNameAndValues.Data, reRoute));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var urlMatch = _urlMatcher.Match(upstreamUrlPath, reRoute.UpstreamTemplatePattern);
 | 
			
		||||
 | 
			
		||||
                if (urlMatch.Data.Match)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
        ServicesAreEmptyError,
 | 
			
		||||
        UnableToFindServiceDiscoveryProviderError,
 | 
			
		||||
        UnableToFindLoadBalancerError,
 | 
			
		||||
        RequestTimedOutError
 | 
			
		||||
        RequestTimedOutError,
 | 
			
		||||
        UnableToFindQoSProviderError
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ using Ocelot.LoadBalancer.LoadBalancers;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.QueryStrings.Middleware;
 | 
			
		||||
using Ocelot.ServiceDiscovery;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.LoadBalancer.Middleware
 | 
			
		||||
{
 | 
			
		||||
@@ -31,7 +30,7 @@ namespace Ocelot.LoadBalancer.Middleware
 | 
			
		||||
        {
 | 
			
		||||
            _logger.LogDebug("started calling load balancing middleware");
 | 
			
		||||
 | 
			
		||||
            var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.LoadBalancerKey);
 | 
			
		||||
            var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
 | 
			
		||||
            if(loadBalancer.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                SetPipelineError(loadBalancer.Errors);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -18,7 +19,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            string contentType, 
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos)
 | 
			
		||||
            IQoSProvider qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            var request = await new RequestBuilder()
 | 
			
		||||
                .WithHttpMethod(httpMethod)
 | 
			
		||||
@@ -30,7 +31,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
                .WithRequestId(requestId)
 | 
			
		||||
                .WithCookies(cookies)
 | 
			
		||||
                .WithIsQos(isQos)
 | 
			
		||||
                .WithQos(qos)
 | 
			
		||||
                .WithQos(qosProvider)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<Request>(request);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -17,6 +17,6 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            string contentType,
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos);
 | 
			
		||||
            IQoSProvider qosProvider);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ using System.Net.Http.Headers;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Primitives;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
        private IRequestCookieCollection _cookies;
 | 
			
		||||
        private readonly string[] _unsupportedHeaders = {"host"};
 | 
			
		||||
        private bool _isQos;
 | 
			
		||||
        private QoSOptions _qos;
 | 
			
		||||
        private IQoSProvider _qoSProvider;
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithHttpMethod(string httpMethod)
 | 
			
		||||
        {
 | 
			
		||||
@@ -80,9 +80,9 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithQos(QoSOptions qos)
 | 
			
		||||
        public RequestBuilder WithQos(IQoSProvider qoSProvider)
 | 
			
		||||
        {
 | 
			
		||||
            _qos = qos;
 | 
			
		||||
            _qoSProvider = qoSProvider;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -105,7 +105,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
 | 
			
		||||
            var cookieContainer = CreateCookieContainer(uri);
 | 
			
		||||
 | 
			
		||||
            return new Request(httpRequestMessage, cookieContainer,_isQos,_qos);
 | 
			
		||||
            return new Request(httpRequestMessage, cookieContainer,_isQos, _qoSProvider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Uri CreateUri()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Ocelot.Infrastructure.RequestData;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Ocelot.Request.Builder;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Middleware
 | 
			
		||||
{
 | 
			
		||||
@@ -13,15 +13,18 @@ namespace Ocelot.Request.Middleware
 | 
			
		||||
        private readonly RequestDelegate _next;
 | 
			
		||||
        private readonly IRequestCreator _requestCreator;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly IQosProviderHouse _qosProviderHouse;
 | 
			
		||||
 | 
			
		||||
        public HttpRequestBuilderMiddleware(RequestDelegate next,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            IRequestScopedDataRepository requestScopedDataRepository, 
 | 
			
		||||
            IRequestCreator requestCreator)
 | 
			
		||||
            IRequestCreator requestCreator, 
 | 
			
		||||
            IQosProviderHouse qosProviderHouse)
 | 
			
		||||
            :base(requestScopedDataRepository)
 | 
			
		||||
        {
 | 
			
		||||
            _next = next;
 | 
			
		||||
            _requestCreator = requestCreator;
 | 
			
		||||
            _qosProviderHouse = qosProviderHouse;
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<HttpRequestBuilderMiddleware>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -29,17 +32,35 @@ namespace Ocelot.Request.Middleware
 | 
			
		||||
        {
 | 
			
		||||
            _logger.LogDebug("started calling request builder middleware");
 | 
			
		||||
 | 
			
		||||
            var qosProvider = _qosProviderHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
 | 
			
		||||
 | 
			
		||||
            if (qosProvider.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogDebug("IQosProviderHouse returned an error, setting pipeline error");
 | 
			
		||||
 | 
			
		||||
                SetPipelineError(qosProvider.Errors);
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var buildResult = await _requestCreator
 | 
			
		||||
                .Build(context.Request.Method, DownstreamUrl, context.Request.Body,
 | 
			
		||||
                    context.Request.Headers, context.Request.Cookies, context.Request.QueryString,
 | 
			
		||||
                    context.Request.ContentType, new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier),
 | 
			
		||||
                    DownstreamRoute.ReRoute.IsQos,DownstreamRoute.ReRoute.QosOptions);
 | 
			
		||||
                .Build(context.Request.Method,
 | 
			
		||||
                    DownstreamUrl,
 | 
			
		||||
                    context.Request.Body,
 | 
			
		||||
                    context.Request.Headers,
 | 
			
		||||
                    context.Request.Cookies,
 | 
			
		||||
                    context.Request.QueryString,
 | 
			
		||||
                    context.Request.ContentType,
 | 
			
		||||
                    new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier),
 | 
			
		||||
                    DownstreamRoute.ReRoute.IsQos,
 | 
			
		||||
                    qosProvider.Data);
 | 
			
		||||
 | 
			
		||||
            if (buildResult.IsError)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogDebug("IRequestCreator returned an error, setting pipeline error");
 | 
			
		||||
 | 
			
		||||
                SetPipelineError(buildResult.Errors);
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            _logger.LogDebug("setting upstream request");
 | 
			
		||||
 
 | 
			
		||||
@@ -2,22 +2,27 @@
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request
 | 
			
		||||
{
 | 
			
		||||
    public class Request
 | 
			
		||||
    {
 | 
			
		||||
        public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer,bool isQos, QoSOptions qos)
 | 
			
		||||
        public Request(
 | 
			
		||||
            HttpRequestMessage httpRequestMessage, 
 | 
			
		||||
            CookieContainer cookieContainer,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            IQoSProvider qosProvider)
 | 
			
		||||
        {
 | 
			
		||||
            HttpRequestMessage = httpRequestMessage;
 | 
			
		||||
            CookieContainer = cookieContainer;
 | 
			
		||||
            IsQos = isQos;
 | 
			
		||||
            Qos = qos;
 | 
			
		||||
            QosProvider = qosProvider;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public HttpRequestMessage HttpRequestMessage { get; private set; }
 | 
			
		||||
        public CookieContainer CookieContainer { get; private set; }
 | 
			
		||||
        public bool IsQos { get; private set; }
 | 
			
		||||
        public QoSOptions Qos { get; private set; }
 | 
			
		||||
        public IQoSProvider QosProvider { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Polly;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class CircuitBreakingDelegatingHandler : DelegatingHandler
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly int _exceptionsAllowedBeforeBreaking;
 | 
			
		||||
        private readonly TimeSpan _durationOfBreak;
 | 
			
		||||
        private readonly Policy _circuitBreakerPolicy;
 | 
			
		||||
        private readonly TimeoutPolicy _timeoutPolicy;
 | 
			
		||||
 | 
			
		||||
        public CircuitBreakingDelegatingHandler(
 | 
			
		||||
            int exceptionsAllowedBeforeBreaking, 
 | 
			
		||||
            TimeSpan durationOfBreak,
 | 
			
		||||
            TimeSpan timeoutValue,
 | 
			
		||||
            TimeoutStrategy timeoutStrategy, 
 | 
			
		||||
            IOcelotLogger logger, 
 | 
			
		||||
            HttpMessageHandler innerHandler)
 | 
			
		||||
            : base(innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
			
		||||
 | 
			
		||||
            this._durationOfBreak = durationOfBreak;
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .CircuitBreakerAsync(
 | 
			
		||||
                    exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking,
 | 
			
		||||
                    durationOfBreak: 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.")
 | 
			
		||||
                    );
 | 
			
		||||
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                return await Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync(() => base.SendAsync(request,cancellationToken));
 | 
			
		||||
            }
 | 
			
		||||
            catch (BrokenCircuitException ex)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex);
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpRequestException ex)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Error in CircuitBreakingDelegatingHandler.SendAync", ex);
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsTransientFailure(HttpResponseMessage result)
 | 
			
		||||
        {
 | 
			
		||||
            return result.StatusCode >= HttpStatusCode.InternalServerError;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +1,39 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    internal class HttpClientBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<int, Func<DelegatingHandler>> handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
			
		||||
        private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
			
		||||
 | 
			
		||||
        public HttpClientBuilder WithCircuitBreaker(QoSOptions qos, IOcelotLogger logger, HttpMessageHandler innerHandler)
 | 
			
		||||
        public HttpClientBuilder WithQoS(IQoSProvider qoSProvider, IOcelotLogger logger, HttpMessageHandler innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            handlers.Add(5000, () => new CircuitBreakingDelegatingHandler(qos.ExceptionsAllowedBeforeBreaking, qos.DurationOfBreak, qos.TimeoutValue, qos.TimeoutStrategy, logger, innerHandler));
 | 
			
		||||
            _handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qoSProvider, logger, innerHandler));
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal HttpClient Build(HttpMessageHandler innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            return handlers.Any() ? new HttpClient(CreateHttpMessageHandler()) : new HttpClient(innerHandler);
 | 
			
		||||
            return _handlers.Any() ? 
 | 
			
		||||
                new HttpClient(CreateHttpMessageHandler()) : 
 | 
			
		||||
                new HttpClient(innerHandler);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private HttpMessageHandler CreateHttpMessageHandler()
 | 
			
		||||
        {
 | 
			
		||||
            HttpMessageHandler httpMessageHandler = new HttpClientHandler();
 | 
			
		||||
 | 
			
		||||
            handlers.OrderByDescending(handler => handler.Key).Select(handler => handler.Value).Reverse().ToList().ForEach(handler =>
 | 
			
		||||
            _handlers
 | 
			
		||||
                .OrderByDescending(handler => handler.Key)
 | 
			
		||||
                .Select(handler => handler.Value)
 | 
			
		||||
                .Reverse()
 | 
			
		||||
                .ToList()
 | 
			
		||||
                .ForEach(handler =>
 | 
			
		||||
            {
 | 
			
		||||
                var delegatingHandler = handler();
 | 
			
		||||
                delegatingHandler.InnerHandler = httpMessageHandler;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,17 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientHttpRequester : IHttpRequester
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
        public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
 | 
			
		||||
@@ -19,13 +19,13 @@ namespace Ocelot.Requester
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
 | 
			
		||||
        {
 | 
			
		||||
            HttpClientBuilder builder = new HttpClientBuilder();    
 | 
			
		||||
            var builder = new HttpClientBuilder();    
 | 
			
		||||
 | 
			
		||||
            using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer })
 | 
			
		||||
            {
 | 
			
		||||
                if (request.IsQos)
 | 
			
		||||
                {
 | 
			
		||||
                    builder.WithCircuitBreaker(request.Qos, _logger, handler);
 | 
			
		||||
                    builder.WithQoS(request.QosProvider, _logger, handler);
 | 
			
		||||
                }           
 | 
			
		||||
 | 
			
		||||
                using (var httpClient = builder.Build(handler))
 | 
			
		||||
@@ -35,10 +35,15 @@ namespace Ocelot.Requester
 | 
			
		||||
                        var response = await httpClient.SendAsync(request.HttpRequestMessage);
 | 
			
		||||
                        return new OkResponse<HttpResponseMessage>(response);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Polly.Timeout.TimeoutRejectedException exception)
 | 
			
		||||
                    catch (TimeoutRejectedException exception)
 | 
			
		||||
                    {
 | 
			
		||||
                        return
 | 
			
		||||
                           new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
 | 
			
		||||
                            new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (BrokenCircuitException exception)
 | 
			
		||||
                    {
 | 
			
		||||
                        return
 | 
			
		||||
                            new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception exception)
 | 
			
		||||
                    {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Requester.QoS;
 | 
			
		||||
using Polly;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class PollyCircuitBreakingDelegatingHandler : DelegatingHandler
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IQoSProvider _qoSProvider;
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
 | 
			
		||||
        public PollyCircuitBreakingDelegatingHandler(
 | 
			
		||||
            IQoSProvider qoSProvider,
 | 
			
		||||
            IOcelotLogger logger, 
 | 
			
		||||
            HttpMessageHandler innerHandler)
 | 
			
		||||
            : base(innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            _qoSProvider = qoSProvider;
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                return await Policy
 | 
			
		||||
                    .WrapAsync(_qoSProvider.CircuitBreaker.CircuitBreakerPolicy, _qoSProvider.CircuitBreaker.TimeoutPolicy)
 | 
			
		||||
                    .ExecuteAsync(() => base.SendAsync(request,cancellationToken));
 | 
			
		||||
            }
 | 
			
		||||
            catch (BrokenCircuitException ex)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open",ex);
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpRequestException ex)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Error in CircuitBreakingDelegatingHandler.SendAync", ex);
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								src/Ocelot/Requester/QoS/IQoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/Ocelot/Requester/QoS/IQoSProviderFactory.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
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
 | 
			
		||||
{
 | 
			
		||||
    public interface IQoSProviderFactory
 | 
			
		||||
    {
 | 
			
		||||
        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(reRoute.QosOptions.TimeoutValue, reRoute.QosOptions.TimeoutStrategy);
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .CircuitBreakerAsync(
 | 
			
		||||
                    exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
 | 
			
		||||
                    durationOfBreak: reRoute.QosOptions.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();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Ocelot/Requester/QoS/UnableToFindQoSProviderError.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester.QoS
 | 
			
		||||
{
 | 
			
		||||
    public class UnableToFindQoSProviderError : Error
 | 
			
		||||
    {
 | 
			
		||||
        public UnableToFindQoSProviderError(string message) 
 | 
			
		||||
            : base(message, OcelotErrorCode.UnableToFindQoSProviderError)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace Ocelot.Responder
 | 
			
		||||
 | 
			
		||||
            if (errors.Any(e => e.Code == OcelotErrorCode.RequestTimedOutError))
 | 
			
		||||
            {
 | 
			
		||||
                return new OkResponse<int>(408);
 | 
			
		||||
                return new OkResponse<int>(503);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<int>(404);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user