diff --git a/src/Elasticsearch.Net/ConnectionPool/SniffingConnectionPool.cs b/src/Elasticsearch.Net/ConnectionPool/SniffingConnectionPool.cs index fba255dd024..5f0accd9ace 100644 --- a/src/Elasticsearch.Net/ConnectionPool/SniffingConnectionPool.cs +++ b/src/Elasticsearch.Net/ConnectionPool/SniffingConnectionPool.cs @@ -17,7 +17,7 @@ public SniffingConnectionPool(IEnumerable nodes, bool randomize = true, ID : base(nodes, randomize, dateTimeProvider) { } public SniffingConnectionPool(IEnumerable nodes, Func nodeScorer, IDateTimeProvider dateTimeProvider = null) - : base(nodes, nodeScorer, false, dateTimeProvider) { } + : base(nodes, nodeScorer, dateTimeProvider) { } /// public override IReadOnlyCollection Nodes diff --git a/src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs b/src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs index 99afb9c22ae..8ab43e4da80 100644 --- a/src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs +++ b/src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs @@ -12,18 +12,36 @@ public class StaticConnectionPool : IConnectionPool private readonly Func _nodeScorer; public StaticConnectionPool(IEnumerable uris, bool randomize = true, IDateTimeProvider dateTimeProvider = null) - : this(uris.Select(uri => new Node(uri)), randomize, dateTimeProvider) { } + : this(uris.Select(uri => new Node(uri)), randomize, null, dateTimeProvider) { } public StaticConnectionPool(IEnumerable nodes, bool randomize = true, IDateTimeProvider dateTimeProvider = null) - : this(nodes, null, randomize, dateTimeProvider) { } + : this(nodes, randomize, null, dateTimeProvider) { } + protected StaticConnectionPool(IEnumerable nodes, bool randomize, int? randomizeSeed = null, IDateTimeProvider dateTimeProvider = null) + { + Randomize = randomize; + Random = !randomize || !randomizeSeed.HasValue + ? new Random() + : new Random(randomizeSeed.Value); + + Initialize(nodes, dateTimeProvider); + } //this constructor is protected because nodeScorer only makes sense on subclasses that support reseeding //otherwise just manually sort `nodes` before instantiating. - protected StaticConnectionPool(IEnumerable nodes, Func nodeScorer = null, bool randomize = true, IDateTimeProvider dateTimeProvider = null) + protected StaticConnectionPool(IEnumerable nodes, Func nodeScorer = null, IDateTimeProvider dateTimeProvider = null) { - nodes.ThrowIfEmpty(nameof(nodes)); + _nodeScorer = nodeScorer; + Initialize(nodes, dateTimeProvider); + } + + private void Initialize(IEnumerable nodes, IDateTimeProvider dateTimeProvider) + { + var nodesProvided = nodes?.ToList() ?? throw new ArgumentNullException(nameof(nodes)); + nodesProvided.ThrowIfEmpty(nameof(nodes)); + DateTimeProvider = dateTimeProvider ?? Net.DateTimeProvider.Default; + string scheme = null; - foreach (var node in nodes) + foreach (var node in nodesProvided) { if (scheme == null) { @@ -34,10 +52,7 @@ protected StaticConnectionPool(IEnumerable nodes, Func nodeSc throw new ArgumentException("Trying to instantiate a connection pool with mixed URI Schemes"); } - DateTimeProvider = dateTimeProvider ?? Net.DateTimeProvider.Default; - Randomize = randomize; - _nodeScorer = nodeScorer; - InternalNodes = SortNodes(nodes) + InternalNodes = SortNodes(nodesProvided) .DistinctBy(n => n.Uri) .ToList(); LastUpdate = DateTimeProvider.Now(); @@ -62,7 +77,7 @@ protected StaticConnectionPool(IEnumerable nodes, Func nodeSc public virtual bool SupportsReseeding => false; /// - public bool UsingSsl { get; } + public bool UsingSsl { get; private set; } protected List AliveNodes { @@ -75,10 +90,10 @@ protected List AliveNodes } } - protected IDateTimeProvider DateTimeProvider { get; } + protected IDateTimeProvider DateTimeProvider { get; private set; } protected List InternalNodes { get; set; } - protected Random Random { get; } = new Random(); + protected Random Random { get; } protected bool Randomize { get; } /// diff --git a/src/Tests/Tests/ClientConcepts/ConnectionPooling/BuildingBlocks/ConnectionPooling.doc.cs b/src/Tests/Tests/ClientConcepts/ConnectionPooling/BuildingBlocks/ConnectionPooling.doc.cs index b095d90069f..b08738ff166 100644 --- a/src/Tests/Tests/ClientConcepts/ConnectionPooling/BuildingBlocks/ConnectionPooling.doc.cs +++ b/src/Tests/Tests/ClientConcepts/ConnectionPooling/BuildingBlocks/ConnectionPooling.doc.cs @@ -7,6 +7,7 @@ using Elasticsearch.Net; using FluentAssertions; using Nest; +using Tests.Configuration; using Tests.Framework; using Tests.XPack.Security.Privileges; @@ -216,20 +217,30 @@ [U] public void Static() } } + //hide + private class SeededRandomConectionPool : StaticConnectionPool + { + public SeededRandomConectionPool(IEnumerable nodes, int seed) + : base(nodes, randomize: true, randomizeSeed: seed, dateTimeProvider: null) + {} + } + // hide [U] public void RandomizedInitialNodes() { - IEnumerable CreatStaticConnectionPools() + IEnumerable CreateSeededPools(int nodeCount, int pools) { - Thread.Sleep(1); - var uris = Enumerable.Range(1, 50).Select(i => new Uri($"https://10.0.0.{i}:9200/")); - yield return new StaticConnectionPool(uris); + var seed = TestConfiguration.Instance.Seed; + var nodes = Enumerable.Range(1, nodeCount) + .Select(i => new Node(new Uri($"https://10.0.0.{i}:9200/"))) + .ToList(); + for(var i = 0; i < nodeCount; i++) + yield return new SeededRandomConectionPool(nodes, seed + i); } - // assertion works on the probability of seeing a Uri other than https://10.0.0.1:9200/ - // as the first value over 50 runs, when randomized. - CreatStaticConnectionPools() - .Take(50) + var connectionPools = CreateSeededPools(100, 100).ToList(); + connectionPools.Should().HaveCount(100); + connectionPools .Select(p => p.CreateView().First().Uri.ToString()) .All(uri => uri == "https://10.0.0.1:9200/") .Should()