plugged load balancer middleware into Ocelot pipeline, load balanced downstream host and port now used by url creator middleware

This commit is contained in:
Tom Gardham-Pallister 2017-02-03 08:00:07 +00:00
parent aef6507da3
commit f285b0e0ad
9 changed files with 54 additions and 26 deletions

View File

@ -6,6 +6,7 @@ namespace Ocelot.Configuration.Builder
{
public class ReRouteBuilder
{
private string _loadBalancerKey;
private string _downstreamPathTemplate;
private string _upstreamTemplate;
private string _upstreamTemplatePattern;
@ -199,6 +200,12 @@ namespace Ocelot.Configuration.Builder
return this;
}
public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
{
_loadBalancerKey = loadBalancerKey;
return this;
}
public ReRoute Build()
{
return new ReRoute(new DownstreamPathTemplate(_downstreamPathTemplate), _upstreamTemplate, _upstreamHttpMethod, _upstreamTemplatePattern,
@ -206,7 +213,7 @@ namespace Ocelot.Configuration.Builder
_requireHttps, _additionalScopes, _scopeSecret), _configHeaderExtractorProperties, _claimToClaims, _routeClaimRequirement,
_isAuthorised, _claimToQueries, _requestIdHeaderKey, _isCached, _fileCacheOptions, _serviceName,
_useServiceDiscovery, _serviceDiscoveryAddress, _serviceDiscoveryProvider, _downstreamScheme, _loadBalancer,
_downstreamHost, _dsPort);
_downstreamHost, _dsPort, _loadBalancerKey);
}
}
}

View File

@ -104,6 +104,9 @@ namespace Ocelot.Configuration.Creator
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Address)
&& !string.IsNullOrEmpty(globalConfiguration?.ServiceDiscoveryProvider?.Provider);
//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.UpstreamTemplate}{fileReRoute.UpstreamHttpMethod}";
ReRoute reRoute;
if (isAuthenticated)
@ -124,7 +127,7 @@ namespace Ocelot.Configuration.Creator
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds),
fileReRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider,
globalConfiguration?.ServiceDiscoveryProvider?.Address, fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort);
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort,loadBalancerKey);
}
reRoute = new ReRoute(new DownstreamPathTemplate(fileReRoute.DownstreamPathTemplate), fileReRoute.UpstreamTemplate,
@ -134,11 +137,10 @@ namespace Ocelot.Configuration.Creator
requestIdKey, isCached, new CacheOptions(fileReRoute.FileCacheOptions.TtlSeconds),
fileReRoute.ServiceName, useServiceDiscovery, globalConfiguration?.ServiceDiscoveryProvider?.Provider,
globalConfiguration?.ServiceDiscoveryProvider?.Address, fileReRoute.DownstreamScheme,
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort);
fileReRoute.LoadBalancer, fileReRoute.DownstreamHost, fileReRoute.DownstreamPort,loadBalancerKey);
var loadBalancer = _loadBalanceFactory.Get(reRoute);
//todo - not sure if this is the correct key, but this is probably the only unique key i can think of
_loadBalancerHouse.Add($"{fileReRoute.UpstreamTemplate}{fileReRoute.UpstreamHttpMethod}", loadBalancer);
_loadBalancerHouse.Add(reRoute.LoadBalancerKey, loadBalancer);
return reRoute;
}

View File

@ -11,8 +11,9 @@ namespace Ocelot.Configuration
List<ClaimToThing> claimsToClaims, Dictionary<string, string> routeClaimsRequirement, bool isAuthorised, List<ClaimToThing> claimsToQueries,
string requestIdKey, bool isCached, CacheOptions fileCacheOptions, string serviceName, bool useServiceDiscovery,
string serviceDiscoveryProvider, string serviceDiscoveryAddress,
string downstreamScheme, string loadBalancer, string downstreamHost, int downstreamPort)
string downstreamScheme, string loadBalancer, string downstreamHost, int downstreamPort, string loadBalancerKey)
{
LoadBalancerKey = loadBalancerKey;
LoadBalancer = loadBalancer;
DownstreamHost = downstreamHost;
DownstreamPort = downstreamPort;
@ -39,6 +40,7 @@ namespace Ocelot.Configuration
ServiceDiscoveryAddress = serviceDiscoveryAddress;
DownstreamScheme = downstreamScheme;
}
public string LoadBalancerKey {get;private set;}
public DownstreamPathTemplate DownstreamPathTemplate { get; private set; }
public string UpstreamTemplate { get; private set; }
public string UpstreamTemplatePattern { get; private set; }

View File

@ -47,15 +47,12 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
var dsScheme = DownstreamRoute.ReRoute.DownstreamScheme;
//todo - get this out of scoped data repo?
var dsHostAndPort = new HostAndPort(DownstreamRoute.ReRoute.DownstreamHost,
DownstreamRoute.ReRoute.DownstreamPort);
var dsHostAndPort = HostAndPort;
var dsUrl = _urlBuilder.Build(dsPath.Data.Value, dsScheme, dsHostAndPort);
if (dsUrl.IsError)
{
//todo - release the lb connection?
_logger.LogDebug("IUrlBuilder returned an error, setting pipeline error");
SetPipelineError(dsUrl.Errors);
@ -70,8 +67,6 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
await _next.Invoke(context);
//todo - release the lb connection?
_logger.LogDebug("succesfully called next middleware");
}
}

View File

@ -31,26 +31,32 @@ namespace Ocelot.LoadBalancer.Middleware
{
_logger.LogDebug("started calling load balancing middleware");
var loadBalancer = _loadBalancerHouse.Get($"{DownstreamRoute.ReRoute.UpstreamTemplate}{DownstreamRoute.ReRoute.UpstreamHttpMethod}");
//todo check reponse and return error
var loadBalancer = _loadBalancerHouse.Get(DownstreamRoute.ReRoute.LoadBalancerKey);
if(loadBalancer.IsError)
{
//set errors and return
}
var response = loadBalancer.Data.Lease();
//todo check reponse and return error
var hostAndPort = loadBalancer.Data.Lease();
if(hostAndPort.IsError)
{
//set errors and return
}
SetHostAndPortForThisRequest(hostAndPort.Data);
SetHostAndPortForThisRequest(response.Data);
_logger.LogDebug("calling next middleware");
//todo - try next middleware if we get an exception make sure we release
//the host and port? Not sure if this is the way to go but we shall see!
try
{
await _next.Invoke(context);
loadBalancer.Data.Release(response.Data);
loadBalancer.Data.Release(hostAndPort.Data);
}
catch (Exception)
{
loadBalancer.Data.Release(response.Data);
loadBalancer.Data.Release(hostAndPort.Data);
_logger.LogDebug("error calling next middleware, exception will be thrown to global handler");
throw;
}

View File

@ -4,7 +4,7 @@ namespace Ocelot.LoadBalancer.Middleware
{
public static class LoadBalancingMiddlewareExtensions
{
public static IApplicationBuilder UseLoadBalancingMiddlewareExtensions(this IApplicationBuilder builder)
public static IApplicationBuilder UseLoadBalancingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoadBalancingMiddleware>();
}

View File

@ -18,6 +18,7 @@ namespace Ocelot.Middleware
using System.Threading.Tasks;
using Authorisation.Middleware;
using Microsoft.AspNetCore.Http;
using Ocelot.LoadBalancer.Middleware;
public static class OcelotMiddlewareExtensions
{
@ -98,6 +99,9 @@ namespace Ocelot.Middleware
// Now we can run any query string transformation logic
builder.UseQueryStringBuilderMiddleware();
// Get the load balancer for this request
builder.UseLoadBalancingMiddleware();
// This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used
builder.UseDownstreamUrlCreatorMiddleware();

View File

@ -36,6 +36,7 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
private HttpResponseMessage _result;
private OkResponse<DownstreamPath> _downstreamPath;
private OkResponse<DownstreamUrl> _downstreamUrl;
private HostAndPort _hostAndPort;
public DownstreamUrlCreatorMiddlewareTests()
{
@ -69,14 +70,25 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
[Fact]
public void should_call_dependencies_correctly()
{
var hostAndPort = new HostAndPort("127.0.0.1", 80);
this.Given(x => x.GivenTheDownStreamRouteIs(new DownstreamRoute(new List<UrlPathPlaceholderNameAndValue>(), new ReRouteBuilder().WithDownstreamPathTemplate("any old string").Build())))
.And(x => x.GivenTheHostAndPortIs(hostAndPort))
.And(x => x.TheUrlReplacerReturns("/api/products/1"))
.And(x => x.TheUrlBuilderReturns("http://www.bbc.co.uk/api/products/1"))
.And(x => x.TheUrlBuilderReturns("http://127.0.0.1:80/api/products/1"))
.When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy();
}
private void GivenTheHostAndPortIs(HostAndPort hostAndPort)
{
_hostAndPort = hostAndPort;
_scopedRepository
.Setup(x => x.Get<HostAndPort>("HostAndPort"))
.Returns(new OkResponse<HostAndPort>(_hostAndPort));
}
private void TheUrlBuilderReturns(string dsUrl)
{
_downstreamUrl = new OkResponse<DownstreamUrl>(new DownstreamUrl(dsUrl));

View File

@ -54,7 +54,7 @@ namespace Ocelot.UnitTests.LoadBalancer
.UseUrls(_url)
.Configure(app =>
{
app.UseLoadBalancingMiddlewareExtensions();
app.UseLoadBalancingMiddleware();
});
_server = new TestServer(builder);