Skip to content

Commit

Permalink
#9 Change backend and endpoint object heirarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher committed Apr 3, 2020
1 parent 012220b commit 29bbb5d
Show file tree
Hide file tree
Showing 21 changed files with 118 additions and 462 deletions.
25 changes: 14 additions & 11 deletions samples/ReverseProxy.Sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,21 @@
}
},
"ReverseProxy": {
"Backends": [
{
"BackendId": "backend1"
}
],
"Endpoints": {
"backend1": [
{
"EndpointId": "backend1/endpoint1",
"Address": "https://localhost:10000/"
"Backends": {
"backend1": {
"Endpoints": {
"backend1/endpoint1": {
"Address": "https://localhost:10000/"
}
}
]
},
"backend2": {
"Endpoints": {
"backend2/endpoint1": {
"Address": "https://localhost:10001/"
}
}
}
},
"Routes": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ namespace Microsoft.ReverseProxy.Core.Abstractions
/// </remarks>
public sealed class Backend : IDeepCloneable<Backend>
{
/// <summary>
/// Unique identifier of this backend. No other backend may specify the same value.
/// </summary>
public string BackendId { get; set; }

/// <summary>
/// Circuit breaker options.
/// </summary>
Expand All @@ -48,6 +43,11 @@ public sealed class Backend : IDeepCloneable<Backend>
/// </summary>
public HealthCheckOptions HealthCheckOptions { get; set; }

/// <summary>
/// The set of backend endpoints associated with this backend.
/// </summary>
public IDictionary<string, BackendEndpoint> Endpoints { get; private set; } = new Dictionary<string, BackendEndpoint>(StringComparer.Ordinal);

/// <summary>
/// Arbitrary key-value pairs that further describe this backend.
/// </summary>
Expand All @@ -58,12 +58,12 @@ Backend IDeepCloneable<Backend>.DeepClone()
{
return new Backend
{
BackendId = BackendId,
CircuitBreakerOptions = CircuitBreakerOptions?.DeepClone(),
QuotaOptions = QuotaOptions?.DeepClone(),
PartitioningOptions = PartitioningOptions?.DeepClone(),
LoadBalancingOptions = LoadBalancingOptions?.DeepClone(),
HealthCheckOptions = HealthCheckOptions?.DeepClone(),
Endpoints = Endpoints.DeepClone(StringComparer.Ordinal),
Metadata = Metadata?.DeepClone(StringComparer.Ordinal),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ public interface IBackendsRepo
/// <summary>
/// Gets the current set of backends.
/// </summary>
Task<IList<Backend>> GetBackendsAsync(CancellationToken cancellation);
Task<IDictionary<string, Backend>> GetBackendsAsync(CancellationToken cancellation);

/// <summary>
/// Sets the current set of backends.
/// </summary>
Task SetBackendsAsync(IList<Backend> backends, CancellationToken cancellation);
Task SetBackendsAsync(IDictionary<string, Backend> backends, CancellationToken cancellation);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
Expand All @@ -11,11 +11,6 @@ namespace Microsoft.ReverseProxy.Core.Abstractions
/// </summary>
public sealed class BackendEndpoint : IDeepCloneable<BackendEndpoint>
{
/// <summary>
/// Unique identifier of this endpoint. This must be globally unique.
/// </summary>
public string EndpointId { get; set; }

/// <summary>
/// Address of this endpoint. E.g. <c>https://127.0.0.1:123/abcd1234/</c>.
/// </summary>
Expand All @@ -31,7 +26,6 @@ BackendEndpoint IDeepCloneable<BackendEndpoint>.DeepClone()
{
return new BackendEndpoint
{
EndpointId = EndpointId,
Address = Address,
Metadata = Metadata?.DeepClone(StringComparer.Ordinal),
};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public static IReverseProxyBuilder AddMetrics(this IReverseProxyBuilder builder)
public static IReverseProxyBuilder AddInMemoryRepos(this IReverseProxyBuilder builder)
{
builder.Services.AddSingleton<IBackendsRepo, InMemoryBackendsRepo>();
builder.Services.AddSingleton<IBackendEndpointsRepo, InMemoryEndpointsRepo>();
builder.Services.AddSingleton<IRoutesRepo, InMemoryRoutesRepo>();

return builder;
Expand Down
9 changes: 0 additions & 9 deletions src/ReverseProxy.Core/Configuration/ProxyConfigLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ internal class ProxyConfigLoader : IHostedService, IDisposable
private readonly IOptions<ProxyConfigLoaderOptions> _options;
private readonly ILogger<ProxyConfigLoader> _logger;
private readonly IBackendsRepo _backendsRepo;
private readonly IBackendEndpointsRepo _endpointsRepo;
private readonly IRoutesRepo _routesRepo;
private readonly IReverseProxyConfigManager _proxyManager;
private readonly IOptionsMonitor<ProxyConfigOptions> _proxyConfig;
Expand All @@ -38,23 +37,20 @@ public ProxyConfigLoader(
IOptions<ProxyConfigLoaderOptions> options,
ILogger<ProxyConfigLoader> logger,
IBackendsRepo backendsRepo,
IBackendEndpointsRepo endpointsRepo,
IRoutesRepo routesRepo,
IReverseProxyConfigManager proxyManager,
IOptionsMonitor<ProxyConfigOptions> proxyConfig)
{
Contracts.CheckValue(options, nameof(options));
Contracts.CheckValue(logger, nameof(logger));
Contracts.CheckValue(backendsRepo, nameof(backendsRepo));
Contracts.CheckValue(endpointsRepo, nameof(endpointsRepo));
Contracts.CheckValue(routesRepo, nameof(routesRepo));
Contracts.CheckValue(proxyManager, nameof(proxyManager));
Contracts.CheckValue(proxyConfig, nameof(proxyConfig));

_options = options;
_logger = logger;
_backendsRepo = backendsRepo;
_endpointsRepo = endpointsRepo;
_routesRepo = routesRepo;
_proxyManager = proxyManager;
_proxyConfig = proxyConfig;
Expand Down Expand Up @@ -95,11 +91,6 @@ private async Task ApplyAsync(ProxyConfigOptions config)
try
{
await _backendsRepo.SetBackendsAsync(config.Backends, CancellationToken.None);
foreach (var kvp in config.Endpoints)
{
await _endpointsRepo.SetEndpointsAsync(kvp.Key, kvp.Value, CancellationToken.None);
}

await _routesRepo.SetRoutesAsync(config.Routes, CancellationToken.None);

var errorReporter = new LoggerConfigErrorReporter(_logger);
Expand Down
3 changes: 1 addition & 2 deletions src/ReverseProxy.Core/Configuration/ProxyConfigOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ namespace Microsoft.ReverseProxy.Core.Configuration
{
internal class ProxyConfigOptions
{
public IList<Backend> Backends { get; } = new List<Backend>();
public IDictionary<string, IList<BackendEndpoint>> Endpoints { get; } = new Dictionary<string, IList<BackendEndpoint>>(StringComparer.Ordinal);
public IDictionary<string, Backend> Backends { get; } = new Dictionary<string, Backend>(StringComparer.Ordinal);
public IList<ProxyRoute> Routes { get; } = new List<ProxyRoute>();
}
}
53 changes: 1 addition & 52 deletions src/ReverseProxy.Core/Service/Config/DynamicConfigBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,19 @@ namespace Microsoft.ReverseProxy.Core.Service
internal class DynamicConfigBuilder : IDynamicConfigBuilder
{
private readonly IBackendsRepo _backendsRepo;
private readonly IBackendEndpointsRepo _endpointsRepo;
private readonly IRoutesRepo _routesRepo;
private readonly IRouteValidator _parsedRouteValidator;

public DynamicConfigBuilder(
IBackendsRepo backendsRepo,
IBackendEndpointsRepo endpointsRepo,
IRoutesRepo routesRepo,
IRouteValidator parsedRouteValidator)
{
Contracts.CheckValue(backendsRepo, nameof(backendsRepo));
Contracts.CheckValue(endpointsRepo, nameof(endpointsRepo));
Contracts.CheckValue(routesRepo, nameof(routesRepo));
Contracts.CheckValue(parsedRouteValidator, nameof(parsedRouteValidator));

_backendsRepo = backendsRepo;
_endpointsRepo = endpointsRepo;
_routesRepo = routesRepo;
_parsedRouteValidator = parsedRouteValidator;
}
Expand All @@ -39,7 +35,7 @@ public async Task<Result<DynamicConfigRoot>> BuildConfigAsync(IConfigErrorReport
{
Contracts.CheckValue(errorReporter, nameof(errorReporter));

var backends = await GetBackendsWithEndpointsAsync(errorReporter, cancellation);
var backends = await _backendsRepo.GetBackendsAsync(cancellation) ?? new Dictionary<string, Backend>(StringComparer.Ordinal);
var routes = await GetRoutesAsync(errorReporter, cancellation);

var config = new DynamicConfigRoot
Expand All @@ -51,53 +47,6 @@ public async Task<Result<DynamicConfigRoot>> BuildConfigAsync(IConfigErrorReport
return Result.Success(config);
}

private async Task<IList<BackendWithEndpoints>> GetBackendsWithEndpointsAsync(IConfigErrorReporter errorReporter, CancellationToken cancellation)
{
var backends = await _backendsRepo.GetBackendsAsync(cancellation);
var sortedBackends = new SortedList<string, BackendWithEndpoints>(backends?.Count ?? 0, StringComparer.Ordinal);
if (backends != null)
{
foreach (var backend in backends)
{
if (sortedBackends.ContainsKey(backend.BackendId))
{
errorReporter.ReportError(ConfigErrors.BackendDuplicateId, backend.BackendId, $"Duplicate backend '{backend.BackendId}'.");
continue;
}

var endpoints = await GetBackendEndpointsAsync(errorReporter, backend.BackendId, cancellation);
sortedBackends.Add(
backend.BackendId,
new BackendWithEndpoints(
backend: backend.DeepClone(),
endpoints: endpoints)); // `this.GetBackendEndpoints` already returns deep-cloned copies
}
}

return sortedBackends.Values;
}

private async Task<IList<BackendEndpoint>> GetBackendEndpointsAsync(IConfigErrorReporter errorReporter, string backendId, CancellationToken cancellation)
{
var endpoints = await _endpointsRepo.GetEndpointsAsync(backendId, cancellation);
var backendEndpoints = new SortedList<string, BackendEndpoint>(endpoints?.Count ?? 0, StringComparer.Ordinal);
if (endpoints != null)
{
foreach (var endpoint in endpoints)
{
if (backendEndpoints.ContainsKey(endpoint.EndpointId))
{
errorReporter.ReportError(ConfigErrors.BackendEndpointDuplicateId, endpoint.EndpointId, $"Duplicate endpoint '{endpoint.EndpointId}'.");
continue;
}

backendEndpoints.Add(endpoint.EndpointId, endpoint.DeepClone());
}
}

return backendEndpoints.Values;
}

private async Task<IList<ParsedRoute>> GetRoutesAsync(IConfigErrorReporter errorReporter, CancellationToken cancellation)
{
var routes = await _routesRepo.GetRoutesAsync(cancellation);
Expand Down
23 changes: 0 additions & 23 deletions src/ReverseProxy.Core/Service/ConfigModel/BackendWithEndpoints.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;
using Microsoft.ReverseProxy.Core.Abstractions;

namespace Microsoft.ReverseProxy.Core.ConfigModel
{
internal class DynamicConfigRoot
{
public IList<BackendWithEndpoints> Backends { get; set; }
public IDictionary<string, Backend> Backends { get; set; }
public IList<ParsedRoute> Routes { get; set; }
}
}
28 changes: 24 additions & 4 deletions src/ReverseProxy.Core/Service/ConfigRepos/InMemoryBackendsRepo.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ReverseProxy.Core.Abstractions;

namespace Microsoft.ReverseProxy.Core.Service
{
internal class InMemoryBackendsRepo : InMemoryListBase<Backend>, IBackendsRepo
internal class InMemoryBackendsRepo : IBackendsRepo
{
private readonly object _syncRoot = new object();
private IDictionary<string, Backend> _items;

/// <inheritdoc/>
public Task<IList<Backend>> GetBackendsAsync(CancellationToken cancellation)
public Task<IDictionary<string, Backend>> GetBackendsAsync(CancellationToken cancellation)
{
return Task.FromResult(Get());
}

/// <inheritdoc/>
public Task SetBackendsAsync(IList<Backend> backends, CancellationToken cancellation)
public Task SetBackendsAsync(IDictionary<string, Backend> backends, CancellationToken cancellation)
{
Set(backends);
return Task.CompletedTask;
}

protected IDictionary<string, Backend> Get()
{
lock (_syncRoot)
{
return _items?.DeepClone(StringComparer.Ordinal);
}
}

protected void Set(IDictionary<string, Backend> items)
{
lock (_syncRoot)
{
_items = items?.DeepClone(StringComparer.Ordinal);
}
}
}
}
Loading

0 comments on commit 29bbb5d

Please sign in to comment.