mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:35:28 +08:00 
			
		
		
		
	* #363 added a test to prove rr lb works, this doesnt have a lock so it isnt perfect, not sure what the tradeoff is between a lock and a bit of randomness, can change to have a lock anytie * #363 had a look at other oss roudn robin lbs and they all use a lock so imlemented a lock
This commit is contained in:
		@@ -10,6 +10,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
    public class RoundRobin : ILoadBalancer
 | 
					    public class RoundRobin : ILoadBalancer
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly Func<Task<List<Service>>> _services;
 | 
					        private readonly Func<Task<List<Service>>> _services;
 | 
				
			||||||
 | 
					        private readonly object _lock = new object();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private int _last;
 | 
					        private int _last;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,6 +22,8 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
					        public async Task<Response<ServiceHostAndPort>> Lease(DownstreamContext downstreamContext)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var services = await _services();
 | 
					            var services = await _services();
 | 
				
			||||||
 | 
					            lock(_lock)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                if (_last >= services.Count)
 | 
					                if (_last >= services.Count)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _last = 0;
 | 
					                    _last = 0;
 | 
				
			||||||
@@ -30,6 +33,7 @@ namespace Ocelot.LoadBalancer.LoadBalancers
 | 
				
			|||||||
                _last++;
 | 
					                _last++;
 | 
				
			||||||
                return new OkResponse<ServiceHostAndPort>(next.HostAndPort);
 | 
					                return new OkResponse<ServiceHostAndPort>(next.HostAndPort);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void Release(ServiceHostAndPort hostAndPort)
 | 
					        public void Release(ServiceHostAndPort hostAndPort)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Builder;
 | 
				
			|||||||
using Microsoft.AspNetCore.Hosting;
 | 
					using Microsoft.AspNetCore.Hosting;
 | 
				
			||||||
using Microsoft.AspNetCore.Http;
 | 
					using Microsoft.AspNetCore.Http;
 | 
				
			||||||
using Ocelot.Configuration.File;
 | 
					using Ocelot.Configuration.File;
 | 
				
			||||||
 | 
					using Ocelot.LoadBalancer.LoadBalancers;
 | 
				
			||||||
using Shouldly;
 | 
					using Shouldly;
 | 
				
			||||||
using TestStack.BDDfy;
 | 
					using TestStack.BDDfy;
 | 
				
			||||||
using Xunit;
 | 
					using Xunit;
 | 
				
			||||||
@@ -26,7 +27,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_load_balance_request()
 | 
					        public void should_load_balance_request_with_least_connection()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var downstreamServiceOneUrl = "http://localhost:50881";
 | 
					            var downstreamServiceOneUrl = "http://localhost:50881";
 | 
				
			||||||
            var downstreamServiceTwoUrl = "http://localhost:50892";
 | 
					            var downstreamServiceTwoUrl = "http://localhost:50892";
 | 
				
			||||||
@@ -41,7 +42,7 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                            DownstreamScheme = "http",
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
                            UpstreamPathTemplate = "/",
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
                            LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" },
 | 
					                            LoadBalancerOptions = new FileLoadBalancerOptions { Type = nameof(LeastConnection) },
 | 
				
			||||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
					                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                new FileHostAndPort
 | 
					                                new FileHostAndPort
 | 
				
			||||||
@@ -72,6 +73,55 @@ namespace Ocelot.AcceptanceTests
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_load_balance_request_with_round_robin()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var downstreamPortOne = 51881;
 | 
				
			||||||
 | 
					            var downstreamPortTwo = 51892;
 | 
				
			||||||
 | 
					            var downstreamServiceOneUrl = $"http://localhost:{downstreamPortOne}";
 | 
				
			||||||
 | 
					            var downstreamServiceTwoUrl = $"http://localhost:{downstreamPortTwo}";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var configuration = new FileConfiguration
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                ReRoutes = new List<FileReRoute>
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        new FileReRoute
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                            DownstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            DownstreamScheme = "http",
 | 
				
			||||||
 | 
					                            UpstreamPathTemplate = "/",
 | 
				
			||||||
 | 
					                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
				
			||||||
 | 
					                            LoadBalancerOptions = new FileLoadBalancerOptions { Type = nameof(RoundRobin) },
 | 
				
			||||||
 | 
					                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                new FileHostAndPort
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    Host = "localhost",
 | 
				
			||||||
 | 
					                                    Port = downstreamPortOne
 | 
				
			||||||
 | 
					                                },
 | 
				
			||||||
 | 
					                                new FileHostAndPort
 | 
				
			||||||
 | 
					                                {
 | 
				
			||||||
 | 
					                                    Host = "localhost",
 | 
				
			||||||
 | 
					                                    Port = downstreamPortTwo
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    GlobalConfiguration = new FileGlobalConfiguration()
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(x => x.GivenProductServiceOneIsRunning(downstreamServiceOneUrl, 200))
 | 
				
			||||||
 | 
					                .And(x => x.GivenProductServiceTwoIsRunning(downstreamServiceTwoUrl, 200))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
				
			||||||
 | 
					                .And(x => _steps.GivenOcelotIsRunning())
 | 
				
			||||||
 | 
					                .When(x => _steps.WhenIGetUrlOnTheApiGatewayMultipleTimes("/", 50))
 | 
				
			||||||
 | 
					                .Then(x => x.ThenTheTwoServicesShouldHaveBeenCalledTimes(50))
 | 
				
			||||||
 | 
					                .And(x => x.ThenBothServicesCalledRealisticAmountOfTimes(24, 26))
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenBothServicesCalledRealisticAmountOfTimes(int bottom, int top)
 | 
					        private void ThenBothServicesCalledRealisticAmountOfTimes(int bottom, int top)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _counterOne.ShouldBeInRange(bottom, top);
 | 
					            _counterOne.ShouldBeInRange(bottom, top);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user