Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert changes for supporting EndpointRoutingMode #1851

Merged
merged 2 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,21 @@
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.SignalR.Common;
using Microsoft.Extensions.Options;

namespace Microsoft.Azure.SignalR
{
internal class DefaultEndpointRouter : DefaultMessageRouter, IEndpointRouter
{
private readonly EndpointRoutingMode _mode;

public DefaultEndpointRouter(IOptions<ServiceOptions> options)
{
_mode = options?.Value.EndpointRoutingMode ?? EndpointRoutingMode.Weighted;
}

/// <summary>
/// Select an endpoint for negotiate request according to the mode
/// Select an endpoint for negotiate request
/// </summary>
/// <param name="context">The http context of the incoming request</param>
/// <param name="endpoints">All the available endpoints</param>
public ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
{
// get primary endpoints snapshot
var availableEndpoints = GetNegotiateEndpoints(endpoints);
return _mode switch
{
EndpointRoutingMode.Random => GetEndpointRandomly(availableEndpoints),
EndpointRoutingMode.LeastConnection => GetEndpointWithLeastConnection(availableEndpoints),
_ => GetEndpointAccordingToWeight(availableEndpoints),
};
return GetEndpointAccordingToWeight(availableEndpoints);
}

/// <summary>
Expand Down Expand Up @@ -69,7 +56,7 @@ private ServiceEndpoint GetEndpointAccordingToWeight(ServiceEndpoint[] available
if (availableEndpoints.Any(endpoint => endpoint.EndpointMetrics.ConnectionCapacity == 0) ||
availableEndpoints.Length == 1)
{
return GetEndpointRandomly(availableEndpoints);
return availableEndpoints[StaticRandom.Next(availableEndpoints.Length)];
}

var we = new int[availableEndpoints.Length];
Expand All @@ -89,38 +76,5 @@ private ServiceEndpoint GetEndpointAccordingToWeight(ServiceEndpoint[] available

return availableEndpoints[Array.FindLastIndex(we, x => x <= index) + 1];
}

/// <summary>
/// Choose endpoint with least connection count
/// </summary>
private ServiceEndpoint GetEndpointWithLeastConnection(ServiceEndpoint[] availableEndpoints)
{
//first check if weight is available or necessary
if (availableEndpoints.Any(endpoint => endpoint.EndpointMetrics.ConnectionCapacity == 0) ||
availableEndpoints.Length == 1)
{
return GetEndpointRandomly(availableEndpoints);
}

var leastConnectionCount = int.MaxValue;
var index = 0;
for (var i = 0; i < availableEndpoints.Length; i++)
{
var endpointMetrics = availableEndpoints[i].EndpointMetrics;
var connectionCount = endpointMetrics.ClientConnectionCount + endpointMetrics.ServerConnectionCount;
if (connectionCount < leastConnectionCount)
{
leastConnectionCount = connectionCount;
index = i;
}
}

return availableEndpoints[index];
}

private static ServiceEndpoint GetEndpointRandomly(ServiceEndpoint[] availableEndpoints)
{
return availableEndpoints[StaticRandom.Next(availableEndpoints.Length)];
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class EndpointRouterDecorator : IEndpointRouter

public EndpointRouterDecorator(IEndpointRouter router = null)
{
_inner = router ?? new DefaultEndpointRouter(null);
_inner = router ?? new DefaultEndpointRouter();
}

public virtual ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
Expand Down
6 changes: 0 additions & 6 deletions src/Microsoft.Azure.SignalR/ServiceOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,5 @@ public int ConnectionCount
/// Gets or sets a function which accepts <see cref="HttpContext"/> and returns a bitmask combining one or more <see cref="HttpTransportType"/> values that specify what transports the service should use to receive HTTP requests.
/// </summary>
public Func<HttpContext, HttpTransportType> TransportTypeDetector { get; set; } = null;

/// <summary>
/// Gets or sets the default endpoint routing mode when using multiple endpoints.
/// <see cref="EndpointRoutingMode.Weighted"/> by default.
/// </summary>
public EndpointRoutingMode EndpointRoutingMode { get; set; } = EndpointRoutingMode.Weighted;
}
}
57 changes: 26 additions & 31 deletions test/Microsoft.Azure.SignalR.Tests/EndpointRouterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Microsoft.Azure.SignalR.Tests
Expand All @@ -14,7 +12,7 @@ public class EndpointRouterTests
[Fact]
public void TestDefaultEndpointRouterWeightedMode()
{
var drt = GetEndpointRouter(EndpointRoutingMode.Weighted);
var drt = new DefaultEndpointRouter();

const int loops = 20;
var context = new RandomContext();
Expand All @@ -37,46 +35,43 @@ public void TestDefaultEndpointRouterWeightedMode()
context.Reset();
}

[Fact]
public void TestDefaultEndpointRouterLeastConnectionMode()
[Theory]
[InlineData(200)]
[InlineData(300)]
[InlineData(400)]
[InlineData(500)]
public void TestDefaultEndpointRouterWeightedModeWhenAutoScaleIsEnabled(int quotaOfScaleUpInstance)
{
var drt = GetEndpointRouter(EndpointRoutingMode.LeastConnection);
var drt = new DefaultEndpointRouter();

const int loops = 10;
var loops = 100 + (quotaOfScaleUpInstance / 5);
var context = new RandomContext();
const double quotaBarForScaleUp = 0.8;

const string small = "small_instance", large = "large_instance";
var uSmall = GenerateServiceEndpoint(100, 0, 90, small);
var uLarge = GenerateServiceEndpoint(1000, 0, 200, large);
var el = new List<ServiceEndpoint>() { uLarge, uSmall };
var endpointA = GenerateServiceEndpoint(quotaOfScaleUpInstance, 0, 80, "a");
var endpointB = GenerateServiceEndpoint(100, 0, 70, "b");
var endpointC = GenerateServiceEndpoint(100, 0, 70, "c");
var el = new List<ServiceEndpoint>() {endpointA, endpointB, endpointC};
context.BenchTest(loops, () =>
{
var ep = drt.GetNegotiateEndpoint(null, el);
ep.EndpointMetrics.ClientConnectionCount++;
var percent = (ep.EndpointMetrics.ClientConnectionCount + ep.EndpointMetrics.ServerConnectionCount) /
(double)ep.EndpointMetrics.ConnectionCapacity;
if (percent > quotaBarForScaleUp)
{
ep.EndpointMetrics.ConnectionCapacity += 100;
}

return ep.Name;
});
var uLargeCount = context.GetCount(large);
var uSmallCount = context.GetCount(small);
Assert.Equal(0, uLargeCount);
Assert.Equal(10, uSmallCount);
context.Reset();
}

private static IEndpointRouter GetEndpointRouter(EndpointRoutingMode mode)
{
var config = new ConfigurationBuilder().Build();
var serviceProvider = new ServiceCollection()
.AddSignalR()
.AddAzureSignalR(
o =>
{
o.EndpointRoutingMode = mode;
})
.Services
.AddSingleton<IConfiguration>(config)
.BuildServiceProvider();
Assert.Equal(context.GetCount("a") + context.GetCount("b") + context.GetCount("c"), loops);
Assert.Equal(quotaOfScaleUpInstance, endpointA.EndpointMetrics.ConnectionCapacity);
Assert.Equal(200, endpointB.EndpointMetrics.ConnectionCapacity);
Assert.Equal(200, endpointC.EndpointMetrics.ConnectionCapacity);

return serviceProvider.GetRequiredService<IEndpointRouter>();
context.Reset();
}

private static ServiceEndpoint GenerateServiceEndpoint(int capacity, int serverConnectionCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public async Task TestContainerWithOneEndpointWithAllDisconnectedConnectionThrow
{
var endpoint = new ServiceEndpoint(ConnectionString1);
var sem = new TestServiceEndpointManager(endpoint);
var router = new DefaultEndpointRouter(null);
var router = new DefaultEndpointRouter();

var container = new TestMultiEndpointServiceConnectionContainer("hub",
e => new TestServiceConnectionContainer(new List<IServiceConnection> {
Expand Down
Loading