mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 06:22:50 +08:00
Feature/move polly (#561)
* added delegate to select last handler * #529 implemented a way we can inject the last delegating handler * wip - moving code * #529 removed loads of qos code and moved it into Ocelot.Provider.Polly
This commit is contained in:
parent
e909cf9ce7
commit
98ba0271be
@ -1,6 +1,4 @@
|
|||||||
using Polly.Timeout;
|
namespace Ocelot.Configuration
|
||||||
|
|
||||||
namespace Ocelot.Configuration
|
|
||||||
{
|
{
|
||||||
public class QoSOptions
|
public class QoSOptions
|
||||||
{
|
{
|
||||||
@ -9,7 +7,9 @@ namespace Ocelot.Configuration
|
|||||||
int durationofBreak,
|
int durationofBreak,
|
||||||
int timeoutValue,
|
int timeoutValue,
|
||||||
string key,
|
string key,
|
||||||
TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
|
//todo - this is never set in Ocelot so always Pessimistic...I guess it doesn't
|
||||||
|
//matter to much.
|
||||||
|
string timeoutStrategy = "Pessimistic")
|
||||||
{
|
{
|
||||||
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
|
||||||
DurationOfBreak = durationofBreak;
|
DurationOfBreak = durationofBreak;
|
||||||
@ -24,9 +24,10 @@ namespace Ocelot.Configuration
|
|||||||
|
|
||||||
public int TimeoutValue { get; }
|
public int TimeoutValue { get; }
|
||||||
|
|
||||||
public TimeoutStrategy TimeoutStrategy { get; }
|
public string TimeoutStrategy { get; }
|
||||||
|
|
||||||
public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
|
public bool UseQos => ExceptionsAllowedBeforeBreaking > 0 && TimeoutValue > 0;
|
||||||
|
|
||||||
public string Key { get; }
|
public string Key { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,12 @@ namespace Ocelot.DependencyInjection
|
|||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
using Ocelot.Responder;
|
using Ocelot.Responder;
|
||||||
using Ocelot.ServiceDiscovery;
|
using Ocelot.ServiceDiscovery;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Ocelot.Infrastructure;
|
using Ocelot.Infrastructure;
|
||||||
using Ocelot.Middleware.Multiplexer;
|
using Ocelot.Middleware.Multiplexer;
|
||||||
using ServiceDiscovery.Providers;
|
|
||||||
using Ocelot.Request.Creator;
|
using Ocelot.Request.Creator;
|
||||||
|
|
||||||
public class OcelotBuilder : IOcelotBuilder
|
public class OcelotBuilder : IOcelotBuilder
|
||||||
@ -75,8 +70,6 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IRegionCreator, RegionCreator>();
|
Services.TryAddSingleton<IRegionCreator, RegionCreator>();
|
||||||
Services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>();
|
Services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>();
|
||||||
Services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>();
|
Services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>();
|
||||||
Services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
|
|
||||||
Services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
|
|
||||||
Services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
|
Services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
|
||||||
Services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
|
Services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
|
||||||
Services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
|
Services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
|
||||||
@ -136,6 +129,7 @@ namespace Ocelot.DependencyInjection
|
|||||||
Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
|
||||||
Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
|
Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
|
||||||
Services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
|
Services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
|
||||||
|
Services.TryAddSingleton<IQoSFactory, QoSFactory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
public IOcelotBuilder AddSingletonDefinedAggregator<T>()
|
||||||
|
@ -45,6 +45,5 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
|
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
|
||||||
<PackageReference Include="Polly" Version="6.0.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,31 +1,28 @@
|
|||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Logging;
|
|
||||||
using Ocelot.Requester.QoS;
|
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
|
using QoS;
|
||||||
|
|
||||||
namespace Ocelot.Requester
|
|
||||||
{
|
|
||||||
public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory
|
public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory
|
||||||
{
|
{
|
||||||
private readonly ITracingHandlerFactory _factory;
|
private readonly ITracingHandlerFactory _tracingFactory;
|
||||||
private readonly IOcelotLoggerFactory _loggerFactory;
|
private readonly IQoSFactory _qoSFactory;
|
||||||
private readonly IQosProviderHouse _qosProviderHouse;
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
public DelegatingHandlerHandlerFactory(IOcelotLoggerFactory loggerFactory,
|
public DelegatingHandlerHandlerFactory(
|
||||||
ITracingHandlerFactory factory,
|
ITracingHandlerFactory tracingFactory,
|
||||||
IQosProviderHouse qosProviderHouse,
|
IQoSFactory qoSFactory,
|
||||||
IServiceProvider serviceProvider)
|
IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_factory = factory;
|
_tracingFactory = tracingFactory;
|
||||||
_loggerFactory = loggerFactory;
|
_qoSFactory = qoSFactory;
|
||||||
_qosProviderHouse = qosProviderHouse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
|
public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
|
||||||
@ -64,19 +61,21 @@ namespace Ocelot.Requester
|
|||||||
|
|
||||||
if (request.HttpHandlerOptions.UseTracing)
|
if (request.HttpHandlerOptions.UseTracing)
|
||||||
{
|
{
|
||||||
handlers.Add(() => (DelegatingHandler)_factory.Get());
|
handlers.Add(() => (DelegatingHandler)_tracingFactory.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.QosOptions.UseQos)
|
if (request.QosOptions.UseQos)
|
||||||
{
|
{
|
||||||
var qosProvider = _qosProviderHouse.Get(request);
|
var handler = _qoSFactory.Get(request);
|
||||||
|
|
||||||
if (qosProvider.IsError)
|
if (handler != null && !handler.IsError)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<List<Func<DelegatingHandler>>>(qosProvider.Errors);
|
handlers.Add(() => handler.Data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ErrorResponse<List<Func<DelegatingHandler>>>(handler?.Errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlers.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new OkResponse<List<Func<DelegatingHandler>>>(handlers);
|
return new OkResponse<List<Func<DelegatingHandler>>>(handlers);
|
||||||
|
@ -132,7 +132,7 @@ namespace Ocelot.Requester
|
|||||||
{
|
{
|
||||||
var cacheKey = $"{request.DownstreamRequest.Method}:{request.DownstreamRequest.OriginalString}";
|
var cacheKey = $"{request.DownstreamRequest.Method}:{request.DownstreamRequest.OriginalString}";
|
||||||
|
|
||||||
this._logger.LogDebug($"Cache key for request is {cacheKey}");
|
_logger.LogDebug($"Cache key for request is {cacheKey}");
|
||||||
|
|
||||||
return cacheKey;
|
return cacheKey;
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,6 @@ using System.Threading.Tasks;
|
|||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
using Ocelot.Responses;
|
using Ocelot.Responses;
|
||||||
using Polly.CircuitBreaker;
|
|
||||||
using Polly.Timeout;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester
|
namespace Ocelot.Requester
|
||||||
{
|
{
|
||||||
@ -35,18 +33,6 @@ namespace Ocelot.Requester
|
|||||||
var response = await httpClient.SendAsync(context.DownstreamRequest.ToHttpRequestMessage());
|
var response = await httpClient.SendAsync(context.DownstreamRequest.ToHttpRequestMessage());
|
||||||
return new OkResponse<HttpResponseMessage>(response);
|
return new OkResponse<HttpResponseMessage>(response);
|
||||||
}
|
}
|
||||||
catch (TimeoutRejectedException exception)
|
|
||||||
{
|
|
||||||
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
|
|
||||||
}
|
|
||||||
catch (TaskCanceledException exception)
|
|
||||||
{
|
|
||||||
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
|
|
||||||
}
|
|
||||||
catch (BrokenCircuitException exception)
|
|
||||||
{
|
|
||||||
return new ErrorResponse<HttpResponseMessage>(new RequestTimedOutError(exception));
|
|
||||||
}
|
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
return new ErrorResponse<HttpResponseMessage>(new UnableToCompleteRequestError(exception));
|
return new ErrorResponse<HttpResponseMessage>(new UnableToCompleteRequestError(exception));
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
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,
|
|
||||||
IOcelotLoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_qoSProvider = qoSProvider;
|
|
||||||
_logger = loggerFactory.CreateLogger<PollyCircuitBreakingDelegatingHandler>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace Ocelot.Requester.QoS
|
|
||||||
{
|
|
||||||
public interface IQoSProvider
|
|
||||||
{
|
|
||||||
CircuitBreaker CircuitBreaker { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
using Ocelot.Configuration;
|
|
||||||
using Ocelot.LoadBalancer.LoadBalancers;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester.QoS
|
|
||||||
{
|
|
||||||
public interface IQoSProviderFactory
|
|
||||||
{
|
|
||||||
IQoSProvider Get(DownstreamReRoute reRoute);
|
|
||||||
}
|
|
||||||
}
|
|
11
src/Ocelot/Requester/QoS/IQosFactory.cs
Normal file
11
src/Ocelot/Requester/QoS/IQosFactory.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Ocelot.Requester.QoS
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using Configuration;
|
||||||
|
using Responses;
|
||||||
|
|
||||||
|
public interface IQoSFactory
|
||||||
|
{
|
||||||
|
Response<DelegatingHandler> Get(DownstreamReRoute request);
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
using Ocelot.Configuration;
|
|
||||||
using Ocelot.Responses;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester.QoS
|
|
||||||
{
|
|
||||||
public interface IQosProviderHouse
|
|
||||||
{
|
|
||||||
Response<IQoSProvider> Get(DownstreamReRoute reRoute);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace Ocelot.Requester.QoS
|
|
||||||
{
|
|
||||||
public class NoQoSProvider : IQoSProvider
|
|
||||||
{
|
|
||||||
public CircuitBreaker CircuitBreaker { get; }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
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(DownstreamReRoute reRoute, IOcelotLoggerFactory loggerFactory)
|
|
||||||
{
|
|
||||||
_logger = loggerFactory.CreateLogger<PollyQoSProvider>();
|
|
||||||
|
|
||||||
_timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromMilliseconds(reRoute.QosOptions.TimeoutValue), reRoute.QosOptions.TimeoutStrategy);
|
|
||||||
|
|
||||||
_circuitBreakerPolicy = Policy
|
|
||||||
.Handle<HttpRequestException>()
|
|
||||||
.Or<TimeoutRejectedException>()
|
|
||||||
.Or<TimeoutException>()
|
|
||||||
.CircuitBreakerAsync(
|
|
||||||
exceptionsAllowedBeforeBreaking: reRoute.QosOptions.ExceptionsAllowedBeforeBreaking,
|
|
||||||
durationOfBreak: TimeSpan.FromMilliseconds(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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
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(DownstreamReRoute reRoute)
|
|
||||||
{
|
|
||||||
if (reRoute.QosOptions.UseQos)
|
|
||||||
{
|
|
||||||
return new PollyQoSProvider(reRoute, _loggerFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new NoQoSProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
33
src/Ocelot/Requester/QoS/QosFactory.cs
Normal file
33
src/Ocelot/Requester/QoS/QosFactory.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace Ocelot.Requester.QoS
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Configuration;
|
||||||
|
using Logging;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Responses;
|
||||||
|
|
||||||
|
public class QoSFactory : IQoSFactory
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly IOcelotLoggerFactory _ocelotLoggerFactory;
|
||||||
|
|
||||||
|
public QoSFactory(IServiceProvider serviceProvider, IOcelotLoggerFactory ocelotLoggerFactory)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
_ocelotLoggerFactory = ocelotLoggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response<DelegatingHandler> Get(DownstreamReRoute request)
|
||||||
|
{
|
||||||
|
var handler = _serviceProvider.GetService<QosDelegatingHandlerDelegate>();
|
||||||
|
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
return new OkResponse<DelegatingHandler>(handler(request, _ocelotLoggerFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ErrorResponse<DelegatingHandler>(new UnableToFindQoSProviderError($"could not find qosProvider for {request.DownstreamScheme}{request.DownstreamAddresses}{request.DownstreamPathTemplate}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,53 +0,0 @@
|
|||||||
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(DownstreamReRoute reRoute)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_qoSProviders.TryGetValue(reRoute.QosOptions.Key, out var qosProvider))
|
|
||||||
{
|
|
||||||
if (reRoute.QosOptions.UseQos && qosProvider.CircuitBreaker == null)
|
|
||||||
{
|
|
||||||
qosProvider = _qoSProviderFactory.Get(reRoute);
|
|
||||||
Add(reRoute.QosOptions.Key, qosProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OkResponse<IQoSProvider>(_qoSProviders[reRoute.QosOptions.Key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
qosProvider = _qoSProviderFactory.Get(reRoute);
|
|
||||||
Add(reRoute.QosOptions.Key, 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.QosOptions.Key}, exception was {ex}")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Add(string key, IQoSProvider qosProvider)
|
|
||||||
{
|
|
||||||
_qoSProviders.AddOrUpdate(key, qosProvider, (x, y) => qosProvider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,7 @@
|
|||||||
using System;
|
namespace Ocelot.Requester.QoS
|
||||||
using System.Collections.Generic;
|
{
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Ocelot.Errors;
|
using Ocelot.Errors;
|
||||||
|
|
||||||
namespace Ocelot.Requester.QoS
|
|
||||||
{
|
|
||||||
public class UnableToFindQoSProviderError : Error
|
public class UnableToFindQoSProviderError : Error
|
||||||
{
|
{
|
||||||
public UnableToFindQoSProviderError(string message)
|
public UnableToFindQoSProviderError(string message)
|
||||||
|
8
src/Ocelot/Requester/QosDelegatingHandlerDelegate.cs
Normal file
8
src/Ocelot/Requester/QosDelegatingHandlerDelegate.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Ocelot.Requester
|
||||||
|
{
|
||||||
|
using System.Net.Http;
|
||||||
|
using Configuration;
|
||||||
|
using Logging;
|
||||||
|
|
||||||
|
public delegate DelegatingHandler QosDelegatingHandlerDelegate(DownstreamReRoute reRoute, IOcelotLoggerFactory logger);
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Ocelot.Errors;
|
|
||||||
|
|
||||||
namespace Ocelot.Requester
|
|
||||||
{
|
|
||||||
public class RequestTimedOutError : Error
|
|
||||||
{
|
|
||||||
public RequestTimedOutError(Exception exception)
|
|
||||||
: base($"Timeout making http request, exception: {exception}", OcelotErrorCode.RequestTimedOutError)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
namespace Ocelot.AcceptanceTests
|
|
||||||
{
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Ocelot.Configuration.File;
|
|
||||||
using TestStack.BDDfy;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
public class QoSTests : IDisposable
|
|
||||||
{
|
|
||||||
private readonly Steps _steps;
|
|
||||||
private int _requestCount;
|
|
||||||
private readonly ServiceHandler _serviceHandler;
|
|
||||||
|
|
||||||
public QoSTests()
|
|
||||||
{
|
|
||||||
_serviceHandler = new ServiceHandler();
|
|
||||||
_steps = new Steps();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void should_not_timeout()
|
|
||||||
{
|
|
||||||
var configuration = new FileConfiguration
|
|
||||||
{
|
|
||||||
ReRoutes = new List<FileReRoute>
|
|
||||||
{
|
|
||||||
new FileReRoute
|
|
||||||
{
|
|
||||||
DownstreamPathTemplate = "/",
|
|
||||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
||||||
{
|
|
||||||
new FileHostAndPort
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 51569,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DownstreamScheme = "http",
|
|
||||||
UpstreamPathTemplate = "/",
|
|
||||||
UpstreamHttpMethod = new List<string> { "Post" },
|
|
||||||
QoSOptions = new FileQoSOptions
|
|
||||||
{
|
|
||||||
TimeoutValue = 1000,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51569", 200, string.Empty, 10))
|
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
|
||||||
.And(x => _steps.GivenOcelotIsRunning())
|
|
||||||
.And(x => _steps.GivenThePostHasContent("postContent"))
|
|
||||||
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
|
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.BDDfy();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void should_timeout()
|
|
||||||
{
|
|
||||||
var configuration = new FileConfiguration
|
|
||||||
{
|
|
||||||
ReRoutes = new List<FileReRoute>
|
|
||||||
{
|
|
||||||
new FileReRoute
|
|
||||||
{
|
|
||||||
DownstreamPathTemplate = "/",
|
|
||||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
||||||
{
|
|
||||||
new FileHostAndPort
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 51579,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DownstreamScheme = "http",
|
|
||||||
UpstreamPathTemplate = "/",
|
|
||||||
UpstreamHttpMethod = new List<string> { "Post" },
|
|
||||||
QoSOptions = new FileQoSOptions
|
|
||||||
{
|
|
||||||
TimeoutValue = 10,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51579", 201, string.Empty, 1000))
|
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
|
||||||
.And(x => _steps.GivenOcelotIsRunning())
|
|
||||||
.And(x => _steps.GivenThePostHasContent("postContent"))
|
|
||||||
.When(x => _steps.WhenIPostUrlOnTheApiGateway("/"))
|
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.BDDfy();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void should_open_circuit_breaker_then_close()
|
|
||||||
{
|
|
||||||
var configuration = new FileConfiguration
|
|
||||||
{
|
|
||||||
ReRoutes = new List<FileReRoute>
|
|
||||||
{
|
|
||||||
new FileReRoute
|
|
||||||
{
|
|
||||||
DownstreamPathTemplate = "/",
|
|
||||||
DownstreamScheme = "http",
|
|
||||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
||||||
{
|
|
||||||
new FileHostAndPort
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 51892,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpstreamPathTemplate = "/",
|
|
||||||
UpstreamHttpMethod = new List<string> { "Get" },
|
|
||||||
QoSOptions = new FileQoSOptions
|
|
||||||
{
|
|
||||||
ExceptionsAllowedBeforeBreaking = 1,
|
|
||||||
TimeoutValue = 500,
|
|
||||||
DurationOfBreak = 1000
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51892", "Hello from Laura"))
|
|
||||||
.Given(x => _steps.GivenThereIsAConfiguration(configuration))
|
|
||||||
.Given(x => _steps.GivenOcelotIsRunning())
|
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
|
||||||
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.Given(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Given(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.Given(x => x.GivenIWaitMilliseconds(3000))
|
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
|
||||||
.BDDfy();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void open_circuit_should_not_effect_different_reRoute()
|
|
||||||
{
|
|
||||||
var configuration = new FileConfiguration
|
|
||||||
{
|
|
||||||
ReRoutes = new List<FileReRoute>
|
|
||||||
{
|
|
||||||
new FileReRoute
|
|
||||||
{
|
|
||||||
DownstreamPathTemplate = "/",
|
|
||||||
DownstreamScheme = "http",
|
|
||||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
||||||
{
|
|
||||||
new FileHostAndPort
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 51872,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpstreamPathTemplate = "/",
|
|
||||||
UpstreamHttpMethod = new List<string> { "Get" },
|
|
||||||
QoSOptions = new FileQoSOptions
|
|
||||||
{
|
|
||||||
ExceptionsAllowedBeforeBreaking = 1,
|
|
||||||
TimeoutValue = 500,
|
|
||||||
DurationOfBreak = 1000
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new FileReRoute
|
|
||||||
{
|
|
||||||
DownstreamPathTemplate = "/",
|
|
||||||
DownstreamScheme = "http",
|
|
||||||
DownstreamHostAndPorts = new List<FileHostAndPort>
|
|
||||||
{
|
|
||||||
new FileHostAndPort
|
|
||||||
{
|
|
||||||
Host = "localhost",
|
|
||||||
Port = 51880,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpstreamPathTemplate = "/working",
|
|
||||||
UpstreamHttpMethod = new List<string> { "Get" },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAPossiblyBrokenServiceRunningOn("http://localhost:51872", "Hello from Laura"))
|
|
||||||
.And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", 200, "Hello from Tom", 0))
|
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
|
||||||
.And(x => _steps.GivenOcelotIsRunning())
|
|
||||||
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
|
||||||
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/working"))
|
|
||||||
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
|
|
||||||
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.And(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.And(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.ServiceUnavailable))
|
|
||||||
.And(x => x.GivenIWaitMilliseconds(3000))
|
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
|
||||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
|
||||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
|
||||||
.BDDfy();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenIWaitMilliseconds(int ms)
|
|
||||||
{
|
|
||||||
Thread.Sleep(ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenThereIsAPossiblyBrokenServiceRunningOn(string url, string responseBody)
|
|
||||||
{
|
|
||||||
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
|
|
||||||
{
|
|
||||||
//circuit starts closed
|
|
||||||
if (_requestCount == 0)
|
|
||||||
{
|
|
||||||
_requestCount++;
|
|
||||||
context.Response.StatusCode = 200;
|
|
||||||
await context.Response.WriteAsync(responseBody);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//request one times out and polly throws exception, circuit opens
|
|
||||||
if (_requestCount == 1)
|
|
||||||
{
|
|
||||||
_requestCount++;
|
|
||||||
await Task.Delay(1000);
|
|
||||||
context.Response.StatusCode = 200;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//after break closes we return 200 OK
|
|
||||||
if (_requestCount == 2)
|
|
||||||
{
|
|
||||||
context.Response.StatusCode = 200;
|
|
||||||
await context.Response.WriteAsync(responseBody);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, int timeout)
|
|
||||||
{
|
|
||||||
_serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
|
|
||||||
{
|
|
||||||
Thread.Sleep(timeout);
|
|
||||||
context.Response.StatusCode = statusCode;
|
|
||||||
await context.Response.WriteAsync(responseBody);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_serviceHandler?.Dispose();
|
|
||||||
_steps.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -831,7 +831,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_fix_145()
|
public void should_not_set_trailing_slash_on_url_template()
|
||||||
{
|
{
|
||||||
var configuration = new FileConfiguration
|
var configuration = new FileConfiguration
|
||||||
{
|
{
|
||||||
@ -851,11 +851,6 @@ namespace Ocelot.AcceptanceTests
|
|||||||
},
|
},
|
||||||
UpstreamPathTemplate = "/platform/{url}",
|
UpstreamPathTemplate = "/platform/{url}",
|
||||||
UpstreamHttpMethod = new List<string> { "Get" },
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
QoSOptions = new FileQoSOptions {
|
|
||||||
ExceptionsAllowedBeforeBreaking = 3,
|
|
||||||
DurationOfBreak = 10,
|
|
||||||
TimeoutValue = 5000
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.1.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
|
||||||
<PackageReference Include="Polly" Version="6.0.1" />
|
|
||||||
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
|
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -16,23 +16,28 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Ocelot.UnitTests.Requester
|
namespace Ocelot.UnitTests.Requester
|
||||||
{
|
{
|
||||||
|
using Responder;
|
||||||
|
|
||||||
public class DelegatingHandlerHandlerProviderFactoryTests
|
public class DelegatingHandlerHandlerProviderFactoryTests
|
||||||
{
|
{
|
||||||
private DelegatingHandlerHandlerFactory _factory;
|
private DelegatingHandlerHandlerFactory _factory;
|
||||||
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
|
||||||
private DownstreamReRoute _request;
|
private DownstreamReRoute _request;
|
||||||
private Response<List<Func<DelegatingHandler>>> _result;
|
private Response<List<Func<DelegatingHandler>>> _result;
|
||||||
private readonly Mock<IQosProviderHouse> _qosProviderHouse;
|
private readonly Mock<IQoSFactory> _qosFactory;
|
||||||
private readonly Mock<ITracingHandlerFactory> _tracingFactory;
|
private readonly Mock<ITracingHandlerFactory> _tracingFactory;
|
||||||
private IServiceProvider _serviceProvider;
|
private IServiceProvider _serviceProvider;
|
||||||
private readonly IServiceCollection _services;
|
private readonly IServiceCollection _services;
|
||||||
|
private readonly QosDelegatingHandlerDelegate _qosDelegate;
|
||||||
|
|
||||||
public DelegatingHandlerHandlerProviderFactoryTests()
|
public DelegatingHandlerHandlerProviderFactoryTests()
|
||||||
{
|
{
|
||||||
|
_qosDelegate = (a, b) => new FakeQoSHandler();
|
||||||
_tracingFactory = new Mock<ITracingHandlerFactory>();
|
_tracingFactory = new Mock<ITracingHandlerFactory>();
|
||||||
_qosProviderHouse = new Mock<IQosProviderHouse>();
|
_qosFactory = new Mock<IQoSFactory>();
|
||||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
_services = new ServiceCollection();
|
_services = new ServiceCollection();
|
||||||
|
_services.AddSingleton(_qosDelegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -56,8 +61,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheTracingFactoryReturns())
|
.And(x => GivenTheTracingFactoryReturns())
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
@ -67,7 +72,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(3))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(3))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
||||||
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5))
|
.And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +98,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheTracingFactoryReturns())
|
.And(x => GivenTheTracingFactoryReturns())
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerFour, FakeDelegatingHandlerThree>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerFour, FakeDelegatingHandlerThree>())
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
@ -104,7 +109,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) //second from config
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2)) //second from config
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(3)) //third from config (global)
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(3)) //third from config (global)
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
||||||
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5))
|
.And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +134,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheTracingFactoryReturns())
|
.And(x => GivenTheTracingFactoryReturns())
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
@ -140,7 +145,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(2))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(2))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(3))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(3))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(4))
|
||||||
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(5))
|
.And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(5))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,8 +169,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheTracingFactoryReturns())
|
.And(x => GivenTheTracingFactoryReturns())
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandlerThree, FakeDelegatingHandlerFour>())
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
@ -174,7 +179,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(1))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerFour>(1))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(2))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(3))
|
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(3))
|
||||||
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(4))
|
.And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(4))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,8 +199,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheTracingFactoryReturns())
|
.And(x => GivenTheTracingFactoryReturns())
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
@ -203,7 +208,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(0))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandler>(0))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(1))
|
.And(x => ThenHandlerAtPositionIs<FakeDelegatingHandlerTwo>(1))
|
||||||
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(2))
|
.And(x => ThenHandlerAtPositionIs<FakeTracingHandler>(2))
|
||||||
.And(x => ThenHandlerAtPositionIs<PollyCircuitBreakingDelegatingHandler>(3))
|
.And(x => ThenHandlerAtPositionIs<FakeQoSHandler>(3))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +230,6 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
|
||||||
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsSpecificDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
.Then(x => ThenThereIsDelegatesInProvider(2))
|
.Then(x => ThenThereIsDelegatesInProvider(2))
|
||||||
@ -247,12 +251,12 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
.And(x => GivenTheServiceProviderReturnsGlobalDelegatingHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
.Then(x => ThenThereIsDelegatesInProvider(3))
|
.Then(x => ThenThereIsDelegatesInProvider(3))
|
||||||
.And(x => ThenTheDelegatesAreAddedCorrectly())
|
.And(x => ThenTheDelegatesAreAddedCorrectly())
|
||||||
.And(x => ThenItIsPolly(2))
|
.And(x => ThenItIsQosHandler(2))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,11 +291,11 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new OkResponse<IQoSProvider>(It.IsAny<PollyQoSProvider>())))
|
.And(x => GivenTheQosFactoryReturns(new FakeQoSHandler()))
|
||||||
.And(x => GivenTheServiceProviderReturnsNothing())
|
.And(x => GivenTheServiceProviderReturnsNothing())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
.Then(x => ThenThereIsDelegatesInProvider(1))
|
.Then(x => ThenThereIsDelegatesInProvider(1))
|
||||||
.And(x => ThenItIsPolly(0))
|
.And(x => ThenItIsQosHandler(0))
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +313,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
.WithHttpHandlerOptions(new HttpHandlerOptions(true, true, false, true)).WithLoadBalancerKey("").Build();
|
||||||
|
|
||||||
this.Given(x => GivenTheFollowingRequest(reRoute))
|
this.Given(x => GivenTheFollowingRequest(reRoute))
|
||||||
.And(x => GivenTheQosProviderHouseReturns(new ErrorResponse<IQoSProvider>(It.IsAny<Error>())))
|
.And(x => GivenTheQosFactoryReturnsError())
|
||||||
.And(x => GivenTheServiceProviderReturnsNothing())
|
.And(x => GivenTheServiceProviderReturnsNothing())
|
||||||
.When(x => WhenIGet())
|
.When(x => WhenIGet())
|
||||||
.Then(x => ThenAnErrorIsReturned())
|
.Then(x => ThenAnErrorIsReturned())
|
||||||
@ -378,18 +382,25 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
handlerTwo.Order.ShouldBe(2);
|
handlerTwo.Order.ShouldBe(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheQosProviderHouseReturns(Response<IQoSProvider> qosProvider)
|
private void GivenTheQosFactoryReturns(DelegatingHandler handler)
|
||||||
{
|
{
|
||||||
_qosProviderHouse
|
_qosFactory
|
||||||
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
|
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
|
||||||
.Returns(qosProvider);
|
.Returns(new OkResponse<DelegatingHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenItIsPolly(int i)
|
private void GivenTheQosFactoryReturnsError()
|
||||||
|
{
|
||||||
|
_qosFactory
|
||||||
|
.Setup(x => x.Get(It.IsAny<DownstreamReRoute>()))
|
||||||
|
.Returns(new ErrorResponse<DelegatingHandler>(new AnyError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThenItIsQosHandler(int i)
|
||||||
{
|
{
|
||||||
var delegates = _result.Data;
|
var delegates = _result.Data;
|
||||||
var del = delegates[i].Invoke();
|
var del = delegates[i].Invoke();
|
||||||
del.ShouldBeOfType<PollyCircuitBreakingDelegatingHandler>();
|
del.ShouldBeOfType<FakeQoSHandler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThenThereIsDelegatesInProvider(int count)
|
private void ThenThereIsDelegatesInProvider(int count)
|
||||||
@ -406,7 +417,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
private void WhenIGet()
|
private void WhenIGet()
|
||||||
{
|
{
|
||||||
_serviceProvider = _services.BuildServiceProvider();
|
_serviceProvider = _services.BuildServiceProvider();
|
||||||
_factory = new DelegatingHandlerHandlerFactory(_loggerFactory.Object, _tracingFactory.Object, _qosProviderHouse.Object, _serviceProvider);
|
_factory = new DelegatingHandlerHandlerFactory(_tracingFactory.Object, _qosFactory.Object, _serviceProvider);
|
||||||
_result = _factory.Get(_request);
|
_result = _factory.Get(_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,4 +431,8 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
internal class FakeTracingHandler : DelegatingHandler, ITracingHandler
|
internal class FakeTracingHandler : DelegatingHandler, ITracingHandler
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class FakeQoSHandler : DelegatingHandler
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
|
|
||||||
private void ThenTheErrorIsTimeout()
|
private void ThenTheErrorIsTimeout()
|
||||||
{
|
{
|
||||||
_response.Errors[0].ShouldBeOfType<RequestTimedOutError>();
|
_response.Errors[0].ShouldBeOfType<UnableToCompleteRequestError>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenTheHouseReturnsOkHandler()
|
private void GivenTheHouseReturnsOkHandler()
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
using Moq;
|
/*
|
||||||
|
namespace Ocelot.UnitTests.Requester
|
||||||
|
{
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
@ -8,8 +12,6 @@ using System.Collections.Generic;
|
|||||||
using TestStack.BDDfy;
|
using TestStack.BDDfy;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Ocelot.UnitTests.Requester
|
|
||||||
{
|
|
||||||
public class QoSProviderFactoryTests
|
public class QoSProviderFactoryTests
|
||||||
{
|
{
|
||||||
private readonly IQoSProviderFactory _factory;
|
private readonly IQoSProviderFactory _factory;
|
||||||
@ -22,10 +24,9 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
{
|
{
|
||||||
_logger = new Mock<IOcelotLogger>();
|
_logger = new Mock<IOcelotLogger>();
|
||||||
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
_loggerFactory = new Mock<IOcelotLoggerFactory>();
|
||||||
_loggerFactory
|
var services = new ServiceCollection();
|
||||||
.Setup(x => x.CreateLogger<PollyQoSProvider>())
|
var provider = services.BuildServiceProvider();
|
||||||
.Returns(_logger.Object);
|
_factory = new QoSProviderFactory(_loggerFactory.Object, provider);
|
||||||
_factory = new QoSProviderFactory(_loggerFactory.Object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -46,7 +47,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_return_polly_qos_provider()
|
public void should_return_delegate_provider()
|
||||||
{
|
{
|
||||||
var qosOptions = new QoSOptionsBuilder()
|
var qosOptions = new QoSOptionsBuilder()
|
||||||
.WithTimeoutValue(100)
|
.WithTimeoutValue(100)
|
||||||
@ -61,7 +62,7 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
|
|
||||||
this.Given(x => x.GivenAReRoute(reRoute))
|
this.Given(x => x.GivenAReRoute(reRoute))
|
||||||
.When(x => x.WhenIGetTheQoSProvider())
|
.When(x => x.WhenIGetTheQoSProvider())
|
||||||
.Then(x => x.ThenTheQoSProviderIsReturned<PollyQoSProvider>())
|
.Then(x => x.ThenTheQoSProviderIsReturned<FakeProvider>())
|
||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,4 +81,13 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
_result.ShouldBeOfType<T>();
|
_result.ShouldBeOfType<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class FakeProvider : IQoSProvider
|
||||||
|
{
|
||||||
|
public T CircuitBreaker<T>()
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Moq;
|
/*
|
||||||
|
using Moq;
|
||||||
using Ocelot.Configuration;
|
using Ocelot.Configuration;
|
||||||
using Ocelot.Configuration.Builder;
|
using Ocelot.Configuration.Builder;
|
||||||
using Ocelot.Requester.QoS;
|
using Ocelot.Requester.QoS;
|
||||||
@ -176,12 +177,19 @@ namespace Ocelot.UnitTests.Requester
|
|||||||
|
|
||||||
class FakeQoSProvider : IQoSProvider
|
class FakeQoSProvider : IQoSProvider
|
||||||
{
|
{
|
||||||
public CircuitBreaker CircuitBreaker { get; }
|
T IQoSProvider.CircuitBreaker<T>()
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakePollyQoSProvider : IQoSProvider
|
class FakePollyQoSProvider : IQoSProvider
|
||||||
{
|
{
|
||||||
public CircuitBreaker CircuitBreaker { get; }
|
T IQoSProvider.CircuitBreaker<T>()
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user