massive refactor to handle creating load balancer first time a re route is called

This commit is contained in:
Tom Gardham-Pallister
2017-11-08 21:26:49 +00:00
parent ab14df9127
commit e43732290a
33 changed files with 294 additions and 319 deletions

View File

@ -26,13 +26,14 @@ namespace Ocelot.Configuration.Builder
private string _downstreamHost;
private int _downstreamPort;
private string _loadBalancer;
private ServiceProviderConfiguration _serviceProviderConfiguraion;
private bool _useQos;
private QoSOptions _qosOptions;
private HttpHandlerOptions _httpHandlerOptions;
public bool _enableRateLimiting;
public RateLimitOptions _rateLimitOptions;
private string _authenticationProviderKey;
private bool _useServiceDiscovery;
private string _serviceName;
public ReRouteBuilder WithLoadBalancer(string loadBalancer)
{
@ -154,12 +155,6 @@ namespace Ocelot.Configuration.Builder
return this;
}
public ReRouteBuilder WithServiceProviderConfiguraion(ServiceProviderConfiguration serviceProviderConfiguraion)
{
_serviceProviderConfiguraion = serviceProviderConfiguraion;
return this;
}
public ReRouteBuilder WithAuthenticationOptions(AuthenticationOptions authenticationOptions)
{
_authenticationOptions = authenticationOptions;
@ -190,6 +185,18 @@ namespace Ocelot.Configuration.Builder
return this;
}
public ReRouteBuilder WithUseServiceDiscovery(bool useServiceDiscovery)
{
_useServiceDiscovery = useServiceDiscovery;
return this;
}
public ReRouteBuilder WithServiceName(string serviceName)
{
_serviceName = serviceName;
return this;
}
public ReRoute Build()
{
return new ReRoute(
@ -212,12 +219,13 @@ namespace Ocelot.Configuration.Builder
_downstreamHost,
_downstreamPort,
_loadBalancerKey,
_serviceProviderConfiguraion,
_useQos,
_qosOptions,
_enableRateLimiting,
_rateLimitOptions,
_httpHandlerOptions);
_httpHandlerOptions,
_useServiceDiscovery,
_serviceName);
}
}
}

View File

@ -2,38 +2,10 @@ namespace Ocelot.Configuration.Builder
{
public class ServiceProviderConfigurationBuilder
{
private string _serviceName;
private string _downstreamHost;
private int _downstreamPort;
private bool _userServiceDiscovery;
private string _serviceDiscoveryProvider;
private string _serviceDiscoveryProviderHost;
private int _serviceDiscoveryProviderPort;
public ServiceProviderConfigurationBuilder WithServiceName(string serviceName)
{
_serviceName = serviceName;
return this;
}
public ServiceProviderConfigurationBuilder WithDownstreamHost(string downstreamHost)
{
_downstreamHost = downstreamHost;
return this;
}
public ServiceProviderConfigurationBuilder WithDownstreamPort(int downstreamPort)
{
_downstreamPort = downstreamPort;
return this;
}
public ServiceProviderConfigurationBuilder WithUseServiceDiscovery(bool userServiceDiscovery)
{
_userServiceDiscovery = userServiceDiscovery;
return this;
}
public ServiceProviderConfigurationBuilder WithServiceDiscoveryProvider(string serviceDiscoveryProvider)
{
_serviceDiscoveryProvider = serviceDiscoveryProvider;
@ -52,11 +24,9 @@ namespace Ocelot.Configuration.Builder
return this;
}
public ServiceProviderConfiguration Build()
{
return new ServiceProviderConfiguration(_serviceName, _downstreamHost, _downstreamPort, _userServiceDiscovery,
_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
return new ServiceProviderConfiguration(_serviceDiscoveryProvider, _serviceDiscoveryProviderHost,_serviceDiscoveryProviderPort);
}
}
}

View File

@ -26,7 +26,6 @@ namespace Ocelot.Configuration.Creator
private readonly IOptions<FileConfiguration> _options;
private readonly IConfigurationValidator _configurationValidator;
private readonly IOcelotLogger _logger;
private readonly ILoadBalancerCreator _lbCreator;
private readonly IQoSProviderFactory _qoSProviderFactory;
private readonly IQosProviderHouse _qosProviderHouse;
private readonly IClaimsToThingCreator _claimsToThingCreator;
@ -44,7 +43,6 @@ namespace Ocelot.Configuration.Creator
IOptions<FileConfiguration> options,
IConfigurationValidator configurationValidator,
IOcelotLoggerFactory loggerFactory,
ILoadBalancerCreator lbCreator,
IQoSProviderFactory qoSProviderFactory,
IQosProviderHouse qosProviderHouse,
IClaimsToThingCreator claimsToThingCreator,
@ -59,7 +57,6 @@ namespace Ocelot.Configuration.Creator
IHttpHandlerOptionsCreator httpHandlerOptionsCreator
)
{
_lbCreator = lbCreator;
_regionCreator = regionCreator;
_rateLimitOptionsCreator = rateLimitOptionsCreator;
_requestIdKeyCreator = requestIdKeyCreator;
@ -114,8 +111,10 @@ namespace Ocelot.Configuration.Creator
var ocelotReRoute = await SetUpReRoute(reRoute, fileConfiguration.GlobalConfiguration);
reRoutes.Add(ocelotReRoute);
}
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileConfiguration.GlobalConfiguration);
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath);
return new OcelotConfiguration(reRoutes, fileConfiguration.GlobalConfiguration.AdministrationPath, serviceProviderConfiguration);
}
private async Task<ReRoute> SetUpReRoute(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
@ -128,8 +127,6 @@ namespace Ocelot.Configuration.Creator
var upstreamTemplatePattern = _upstreamTemplatePatternCreator.Create(fileReRoute);
var serviceProviderConfiguration = _serviceProviderConfigCreator.Create(fileReRoute, globalConfiguration);
var authOptionsForRoute = _authOptionsCreator.Create(fileReRoute);
var claimsToHeaders = _claimsToThingCreator.Create(fileReRoute.AddHeadersToRequest);
@ -166,7 +163,6 @@ namespace Ocelot.Configuration.Creator
.WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort)
.WithLoadBalancerKey(reRouteKey)
.WithServiceProviderConfiguraion(serviceProviderConfiguration)
.WithIsQos(fileReRouteOptions.IsQos)
.WithQosOptions(qosOptions)
.WithEnableRateLimiting(fileReRouteOptions.EnableRateLimiting)
@ -174,7 +170,6 @@ namespace Ocelot.Configuration.Creator
.WithHttpHandlerOptions(httpHandlerOptions)
.Build();
await _lbCreator.SetupLoadBalancer(reRoute);
SetupQosProvider(reRoute);
return reRoute;
}

View File

@ -4,6 +4,6 @@ namespace Ocelot.Configuration.Creator
{
public interface IServiceProviderConfigurationCreator
{
ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration);
ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration);
}
}

View File

@ -5,18 +5,11 @@ namespace Ocelot.Configuration.Creator
{
public class ServiceProviderConfigurationCreator : IServiceProviderConfigurationCreator
{
public ServiceProviderConfiguration Create(FileReRoute fileReRoute, FileGlobalConfiguration globalConfiguration)
public ServiceProviderConfiguration Create(FileGlobalConfiguration globalConfiguration)
{
var useServiceDiscovery = !string.IsNullOrEmpty(fileReRoute.ServiceName)
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
var serviceProviderPort = globalConfiguration?.ServiceDiscoveryProvider?.Port ?? 0;
return new ServiceProviderConfigurationBuilder()
.WithServiceName(fileReRoute.ServiceName)
.WithDownstreamHost(fileReRoute.DownstreamHost)
.WithDownstreamPort(fileReRoute.DownstreamPort)
.WithUseServiceDiscovery(useServiceDiscovery)
.WithServiceDiscoveryProvider(globalConfiguration?.ServiceDiscoveryProvider?.Provider)
.WithServiceDiscoveryProviderHost(globalConfiguration?.ServiceDiscoveryProvider?.Host)
.WithServiceDiscoveryProviderPort(serviceProviderPort)

View File

@ -6,5 +6,6 @@ namespace Ocelot.Configuration
{
List<ReRoute> ReRoutes { get; }
string AdministrationPath {get;}
ServiceProviderConfiguration ServiceProviderConfiguration {get;}
}
}

View File

@ -4,13 +4,15 @@ namespace Ocelot.Configuration
{
public class OcelotConfiguration : IOcelotConfiguration
{
public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath)
public OcelotConfiguration(List<ReRoute> reRoutes, string administrationPath, ServiceProviderConfiguration serviceProviderConfiguration)
{
ReRoutes = reRoutes;
AdministrationPath = administrationPath;
ServiceProviderConfiguration = serviceProviderConfiguration;
}
public List<ReRoute> ReRoutes { get; }
public string AdministrationPath {get;}
public ServiceProviderConfiguration ServiceProviderConfiguration {get;}
}
}

View File

@ -25,15 +25,17 @@ namespace Ocelot.Configuration
string downstreamHost,
int downstreamPort,
string reRouteKey,
ServiceProviderConfiguration serviceProviderConfiguraion,
bool isQos,
QoSOptions qosOptions,
bool enableEndpointRateLimiting,
RateLimitOptions ratelimitOptions,
HttpHandlerOptions httpHandlerOptions)
HttpHandlerOptions httpHandlerOptions,
bool useServiceDiscovery,
string serviceName)
{
ServiceName = serviceName;
UseServiceDiscovery = useServiceDiscovery;
ReRouteKey = reRouteKey;
ServiceProviderConfiguraion = serviceProviderConfiguraion;
LoadBalancer = loadBalancer;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
@ -83,9 +85,10 @@ namespace Ocelot.Configuration
public string LoadBalancer {get;private set;}
public string DownstreamHost { get; private set; }
public int DownstreamPort { get; private set; }
public ServiceProviderConfiguration ServiceProviderConfiguraion { get; private set; }
public bool EnableEndpointEndpointRateLimiting { get; private set; }
public RateLimitOptions RateLimitOptions { get; private set; }
public HttpHandlerOptions HttpHandlerOptions { get; private set; }
public bool UseServiceDiscovery {get;private set;}
public string ServiceName {get;private set;}
}
}

View File

@ -2,22 +2,13 @@
{
public class ServiceProviderConfiguration
{
public ServiceProviderConfiguration(string serviceName, string downstreamHost,
int downstreamPort, bool useServiceDiscovery, string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
public ServiceProviderConfiguration(string serviceDiscoveryProvider, string serviceProviderHost, int serviceProviderPort)
{
ServiceName = serviceName;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
UseServiceDiscovery = useServiceDiscovery;
ServiceDiscoveryProvider = serviceDiscoveryProvider;
ServiceProviderHost = serviceProviderHost;
ServiceProviderPort = serviceProviderPort;
}
public string ServiceName { get; }
public string DownstreamHost { get; }
public int DownstreamPort { get; }
public bool UseServiceDiscovery { get; }
public string ServiceDiscoveryProvider { get; }
public string ServiceProviderHost { get; private set; }
public int ServiceProviderPort { get; private set; }

View File

@ -94,7 +94,6 @@ namespace Ocelot.DependencyInjection
.AddJsonFormatters();
services.AddLogging();
services.TryAddSingleton<ILoadBalancerCreator, LoadBalancerCreator>();
services.TryAddSingleton<IRegionCreator, RegionCreator>();
services.TryAddSingleton<IFileConfigurationRepository, FileConfigurationRepository>();
services.TryAddSingleton<IFileConfigurationSetter, FileConfigurationSetter>();

View File

@ -1,10 +0,0 @@
using System.Threading.Tasks;
using Ocelot.Configuration;
namespace Ocelot.LoadBalancer
{
public interface ILoadBalancerCreator
{
Task SetupLoadBalancer(ReRoute reRoute);
}
}

View File

@ -1,24 +0,0 @@
using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.LoadBalancer.LoadBalancers;
namespace Ocelot.LoadBalancer
{
public class LoadBalancerCreator : ILoadBalancerCreator
{
private readonly ILoadBalancerHouse _loadBalancerHouse;
private readonly ILoadBalancerFactory _loadBalanceFactory;
public LoadBalancerCreator(ILoadBalancerHouse loadBalancerHouse, ILoadBalancerFactory loadBalancerFactory)
{
_loadBalancerHouse = loadBalancerHouse;
_loadBalanceFactory = loadBalancerFactory;
}
public async Task SetupLoadBalancer(ReRoute reRoute)
{
var loadBalancer = await _loadBalanceFactory.Get(reRoute);
_loadBalancerHouse.Add(reRoute.ReRouteKey, loadBalancer);
}
}
}

View File

@ -5,6 +5,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers
{
public interface ILoadBalancerFactory
{
Task<ILoadBalancer> Get(ReRoute reRoute);
Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config);
}
}

View File

@ -1,10 +1,11 @@
using Ocelot.Responses;
using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.LoadBalancer.LoadBalancers
{
public interface ILoadBalancerHouse
{
Response<ILoadBalancer> Get(string key);
Response Add(string key, ILoadBalancer loadBalancer);
Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config);
}
}

View File

@ -12,16 +12,16 @@ namespace Ocelot.LoadBalancer.LoadBalancers
_serviceProviderFactory = serviceProviderFactory;
}
public async Task<ILoadBalancer> Get(ReRoute reRoute)
public async Task<ILoadBalancer> Get(ReRoute reRoute, ServiceProviderConfiguration config)
{
var serviceProvider = _serviceProviderFactory.Get(reRoute.ServiceProviderConfiguraion);
var serviceProvider = _serviceProviderFactory.Get(config, reRoute);
switch (reRoute.LoadBalancer)
{
case "RoundRobin":
return new RoundRobinLoadBalancer(async () => await serviceProvider.Get());
case "LeastConnection":
return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceProviderConfiguraion.ServiceName);
return new LeastConnectionLoadBalancer(async () => await serviceProvider.Get(), reRoute.ServiceName);
default:
return new NoLoadBalancer(await serviceProvider.Get());
}

View File

@ -1,33 +1,58 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.LoadBalancer.LoadBalancers
{
public class LoadBalancerHouse : ILoadBalancerHouse
{
private readonly ILoadBalancerFactory _factory;
private readonly Dictionary<string, ILoadBalancer> _loadBalancers;
public LoadBalancerHouse()
public LoadBalancerHouse(ILoadBalancerFactory factory)
{
_factory = factory;
_loadBalancers = new Dictionary<string, ILoadBalancer>();
}
public Response<ILoadBalancer> Get(string key)
public async Task<Response<ILoadBalancer>> Get(ReRoute reRoute, ServiceProviderConfiguration config)
{
ILoadBalancer loadBalancer;
if(_loadBalancers.TryGetValue(key, out loadBalancer))
try
{
return new OkResponse<ILoadBalancer>(_loadBalancers[key]);
ILoadBalancer loadBalancer;
if(_loadBalancers.TryGetValue(reRoute.ReRouteKey, out loadBalancer))
{
loadBalancer = _loadBalancers[reRoute.ReRouteKey];
//todo - we have some duplicate namey type logic in the LoadBalancerFactory...maybe we can do something
//about this..
if((reRoute.LoadBalancer == "RoundRobin" && loadBalancer.GetType() != typeof(RoundRobinLoadBalancer))
|| (reRoute.LoadBalancer == "LeastConnection" && loadBalancer.GetType() != typeof(LeastConnectionLoadBalancer)))
{
loadBalancer = await _factory.Get(reRoute, config);
AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
}
return new OkResponse<ILoadBalancer>(loadBalancer);
}
loadBalancer = await _factory.Get(reRoute, config);
AddLoadBalancer(reRoute.ReRouteKey, loadBalancer);
return new OkResponse<ILoadBalancer>(loadBalancer);
}
return new ErrorResponse<ILoadBalancer>(new List<Ocelot.Errors.Error>()
catch(Exception ex)
{
new UnableToFindLoadBalancerError($"unabe to find load balancer for {key}")
});
return new ErrorResponse<ILoadBalancer>(new List<Ocelot.Errors.Error>()
{
new UnableToFindLoadBalancerError($"unabe to find load balancer for {reRoute.ReRouteKey} exception is {ex}")
});
}
}
public Response Add(string key, ILoadBalancer loadBalancer)
private void AddLoadBalancer(string key, ILoadBalancer loadBalancer)
{
if (!_loadBalancers.ContainsKey(key))
{
@ -36,7 +61,6 @@ namespace Ocelot.LoadBalancer.LoadBalancers
_loadBalancers.Remove(key);
_loadBalancers.Add(key, loadBalancer);
return new OkResponse();
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.Provider;
using Ocelot.Infrastructure.RequestData;
using Ocelot.LoadBalancer.LoadBalancers;
using Ocelot.Logging;
@ -11,6 +12,7 @@ namespace Ocelot.LoadBalancer.Middleware
{
public class LoadBalancingMiddleware : OcelotMiddleware
{
private readonly IOcelotConfigurationProvider _configProvider;
private readonly RequestDelegate _next;
private readonly IOcelotLogger _logger;
private readonly ILoadBalancerHouse _loadBalancerHouse;
@ -18,9 +20,11 @@ namespace Ocelot.LoadBalancer.Middleware
public LoadBalancingMiddleware(RequestDelegate next,
IOcelotLoggerFactory loggerFactory,
IRequestScopedDataRepository requestScopedDataRepository,
ILoadBalancerHouse loadBalancerHouse)
ILoadBalancerHouse loadBalancerHouse,
IOcelotConfigurationProvider configProvider)
: base(requestScopedDataRepository)
{
_configProvider = configProvider;
_next = next;
_logger = loggerFactory.CreateLogger<QueryStringBuilderMiddleware>();
_loadBalancerHouse = loadBalancerHouse;
@ -28,7 +32,9 @@ namespace Ocelot.LoadBalancer.Middleware
public async Task Invoke(HttpContext context)
{
var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.ReRouteKey);
var configuration = await _configProvider.Get();
var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, configuration.Data.ServiceProviderConfiguration);
if(loadBalancer.IsError)
{
_logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");

View File

@ -4,6 +4,6 @@ namespace Ocelot.ServiceDiscovery
{
public interface IServiceDiscoveryProviderFactory
{
IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig);
IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute);
}
}

View File

@ -6,17 +6,17 @@ namespace Ocelot.ServiceDiscovery
{
public class ServiceDiscoveryProviderFactory : IServiceDiscoveryProviderFactory
{
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig)
public IServiceDiscoveryProvider Get(ServiceProviderConfiguration serviceConfig, ReRoute reRoute)
{
if (serviceConfig.UseServiceDiscovery)
if (reRoute.UseServiceDiscovery)
{
return GetServiceDiscoveryProvider(serviceConfig.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
return GetServiceDiscoveryProvider(reRoute.ServiceName, serviceConfig.ServiceDiscoveryProvider, serviceConfig.ServiceProviderHost, serviceConfig.ServiceProviderPort);
}
var services = new List<Service>()
{
new Service(serviceConfig.ServiceName,
new HostAndPort(serviceConfig.DownstreamHost, serviceConfig.DownstreamPort),
new Service(reRoute.ServiceName,
new HostAndPort(reRoute.DownstreamHost, reRoute.DownstreamPort),
string.Empty,
string.Empty,
new string[0])