Skip to content

Commit 5f0f3d9

Browse files
Mpdreamzawelburn
authored and
awelburn
committed
tone max default connections down to 80, add integration tests that proofs connections reuse
added some docs on injecting a custom IConnection add integration test that proofs connections reuse
1 parent a90127c commit 5f0f3d9

File tree

5 files changed

+153
-7
lines changed

5 files changed

+153
-7
lines changed

src/Elasticsearch.Net/Connection/HttpConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ protected virtual void AlterServicePoint(ServicePoint requestServicePoint, Reque
7676
{
7777
requestServicePoint.UseNagleAlgorithm = false;
7878
requestServicePoint.Expect100Continue = false;
79-
requestServicePoint.ConnectionLimit = 10000;
79+
requestServicePoint.ConnectionLimit = 80;
8080
//looking at http://referencesource.microsoft.com/#System/net/System/Net/ServicePoint.cs
8181
//this method only sets internal values and wont actually cause timers and such to be reset
8282
//So it should be idempotent if called with the same parameters

src/Elasticsearch.Net/Connection/InMemoryConnection.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ public class InMemoryConnection : IConnection
1212
private readonly int _statusCode;
1313
private readonly Exception _exception;
1414

15+
/// <summary>
16+
/// Every request will succeed with this overload, note that it won't actually return mocked responses
17+
/// so using this overload might fail if you are using it to test high level bits that need to deserialize the response.
18+
/// </summary>
1519
public InMemoryConnection()
1620
{
1721
_statusCode = 200;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Elasticsearch.Net;
2+
using FluentAssertions;
3+
using Nest;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Tests.Framework;
10+
using System.Net;
11+
12+
namespace Tests.ClientConcepts.Connection
13+
{
14+
public class CustomConnections
15+
{
16+
/**== Custom Connection Implementations
17+
*
18+
* The client abstracts sending the request and creating a response behind `IConnection`
19+
*
20+
* By default the client will use a WebRequest based version on the desktop CLR (.NET 4.5 and up targets)
21+
* and a HttpClient based HttpConnection specifically build for the Core CLR (netstandard 1.6).
22+
*
23+
* The reason for the split is because WebRequest and ServicePoint are not directly available on netstandard 1.6
24+
*
25+
* However the implementation written against WebRequest is the most matured implementation that we weren't ready to it give up.
26+
* There are also a couple of important toggles that are easy to set against a `ServicePoint` that we'd have to give up
27+
* had we jumped on the `HttpClient` completely.
28+
*
29+
* Another limitation is that `HttpClient` has no synchronous code paths and supporting that means doing hacky async patches which definitely
30+
* need time to bake.
31+
*
32+
* So why would you ever want to pass your own `IConnection`? Let's look at a couple of examples
33+
*
34+
*/
35+
36+
public void OverrideHow()
37+
{
38+
var connection = new InMemoryConnection();
39+
var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
40+
var settings = new ConnectionSettings(connectionPool, connection);
41+
var client = new ElasticClient(settings);
42+
}
43+
44+
/**
45+
* Here we create a new `ConnectionSettings` by using the overload that takes a `IConnectionPool` and an `IConnection`.
46+
* We pass it an `InMemoryConnection` which using this constructor will return 200 for everything and never actually perform any IO.
47+
*
48+
* `InMemoryConnection` is great to write unit tests with as there is another overload that takes a fixed response stream to return.
49+
*
50+
*
51+
* === ServicePoint hacking
52+
*
53+
* If you are running on the desktop CLR you can override specific properties for the current `ServicePoint` easily by overriding
54+
* `AlterServicePoint` e.g to change the default connection limit to a specific endpoint from 80 to something higher.
55+
* Remember though that we reuse TCP connections so changing this to something really high should only be done with careful consideration.
56+
*/
57+
58+
public class MySpecialHttpConnection : HttpConnection
59+
{
60+
protected override void AlterServicePoint(ServicePoint requestServicePoint, RequestData requestData)
61+
{
62+
base.AlterServicePoint(requestServicePoint, requestData);
63+
requestServicePoint.ConnectionLimit = 10000;
64+
requestServicePoint.UseNagleAlgorithm = true;
65+
}
66+
67+
}
68+
}
69+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using Tests.Framework;
7+
using Tests.Framework.Integration;
8+
using Tests.Framework.MockData;
9+
using Xunit;
10+
11+
using Elasticsearch.Net;
12+
using Nest;
13+
using FluentAssertions;
14+
using System.Threading;
15+
using System.Reactive.Linq;
16+
using static Nest.Infer;
17+
18+
namespace Tests.Reproduce
19+
{
20+
public class ConnectionReuseCluster : ClusterBase { }
21+
public class ConnectionReuseAndBalancing : IClusterFixture<ConnectionReuseCluster>
22+
{
23+
private readonly ConnectionReuseCluster _cluster;
24+
25+
public ConnectionReuseAndBalancing(ConnectionReuseCluster cluster)
26+
{
27+
_cluster = cluster;
28+
}
29+
30+
public IEnumerable<Project> MockDataGenerator(int numDocuments)
31+
{
32+
foreach (var i in Enumerable.Range(0, numDocuments))
33+
yield return new Project { Name = $"project-{i}" };
34+
}
35+
36+
[I] public async Task IndexAndSearchABunch()
37+
{
38+
var tokenSource = new CancellationTokenSource();
39+
var client = _cluster.Client;
40+
41+
await client.DeleteIndexAsync(Index<Project>());
42+
var observableBulk = client.BulkAll(this.MockDataGenerator(100000), f => f
43+
.MaxDegreeOfParallelism(10)
44+
.BackOffTime(TimeSpan.FromSeconds(10))
45+
.BackOffRetries(2)
46+
.Size(1000)
47+
.RefreshOnCompleted()
48+
, tokenSource.Token);
49+
await observableBulk.ForEachAsync(x => { }, tokenSource.Token);
50+
var statsRequest = new NodesStatsRequest(NodesStatsMetric.Http);
51+
var nodeStats = await client.NodesStatsAsync(statsRequest);
52+
this.AssertHttpStats(nodeStats);
53+
for (var i = 0; i < 10; i++)
54+
{
55+
Parallel.For(0, 1000, async (c) => await client.SearchAsync<Project>(s => s));
56+
57+
nodeStats = await client.NodesStatsAsync(statsRequest);
58+
this.AssertHttpStats(nodeStats);
59+
}
60+
}
61+
62+
private void AssertHttpStats(INodesStatsResponse response)
63+
{
64+
foreach(var node in response.Nodes.Values)
65+
{
66+
node.Http.TotalOpened.Should().BeGreaterThan(2);
67+
node.Http.TotalOpened.Should().BeLessThan(100);
68+
node.Http.CurrentOpen.Should().BeLessThan(100);
69+
}
70+
71+
}
72+
}
73+
}

src/Tests/Tests.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@
220220
<Compile Include="Cat\CatThreadPool\CatThreadPoolUrlTests.cs" />
221221
<Compile Include="ClientConcepts\ConnectionPooling\Dispose\ResponseBuilderDisposeTests.cs" />
222222
<Compile Include="ClientConcepts\ConnectionPooling\Sniffing\AddressParsing.doc.cs" />
223+
<Compile Include="ClientConcepts\Connection\CustomConnections.cs" />
223224
<Compile Include="Cluster\TaskManagement\GetTask\GetTaskApiTests.cs" />
224225
<Compile Include="Cluster\TaskManagement\GetTask\GetTaskUrlTests.cs" />
225226
<Compile Include="CodeStandards\Responses.doc.cs" />
@@ -238,9 +239,11 @@
238239
<Compile Include="Framework\EndpointTests\TestState\AsyncLazy.cs" />
239240
<Compile Include="Framework\EndpointTests\Clusters\IntrusiveOperationCluster.cs" />
240241
<Compile Include="Framework\EndpointTests\Clusters\WritableCluster.cs" />
242+
<Compile Include="Framework\EndpointTests\TestState\ClientMethod.cs" />
241243
<Compile Include="Framework\Extensions\ReadOnlyDictionaryAssertions.cs" />
242244
<Compile Include="Framework\Extensions\ShouldExtensions.cs" />
243245
<Compile Include="Framework\ManagedElasticsearch\FileSystem\INodeFileSystem.cs" />
246+
<Compile Include="Framework\ManagedElasticsearch\Process\ElasticsearchConsoleOut.cs" />
244247
<Compile Include="Framework\MockData\GeoIp.cs" />
245248
<Compile Include="Framework\SerializationTests\DictionarySerializationTests.cs" />
246249
<Compile Include="Framework\VirtualClustering\Audit\Auditor.cs" />
@@ -493,6 +496,7 @@
493496
<Compile Include=".\QueryDsl\Geo\Shape\MultiPoint\GeoMultiPointUsageTests.cs" />
494497
<Compile Include=".\QueryDsl\Geo\Shape\Point\GeoPointUsageTests.cs" />
495498
<Compile Include=".\QueryDsl\Geo\Shape\Polygon\GeoPolygonUsageTests.cs" />
499+
<Compile Include="QueryDsl\ConditionlessWhen.cs" />
496500
<Compile Include="QueryDsl\Geo\Shape\GeoShapeQueryUsageTestsBase.cs" />
497501
<Compile Include=".\QueryDsl\Joining\HasChild\HasChildQueryUsageTests.cs" />
498502
<Compile Include=".\QueryDsl\Joining\HasParent\HasParentQueryUsageTests.cs" />
@@ -615,13 +619,11 @@
615619
<Compile Include="Document\Multiple\UpdateByQuery\UpdateByQueryApiTests.cs" />
616620
<Compile Include="Document\Multiple\UpdateByQuery\UpdateByQueryUrlTests.cs" />
617621
<Compile Include="Framework\EndpointTests\TestState\CallUniqueValues.cs" />
618-
<Compile Include="Framework\EndpointTests\TestState\ClientMethod.cs" />
619-
<Compile Include="Framework\ManagedElasticsearch\Process\ElasticsearchConsoleOut.cs" />
620-
<Compile Include="QueryDsl\ConditionlessWhen.cs" />
621622
<Compile Include="QueryDsl\Joining\ParentId\ParentIdUsageTests.cs" />
622623
<Compile Include="QueryDsl\MatchNoneQueryUsageTests.cs" />
623624
<Compile Include="QueryDsl\NotConditionlessWhen.cs" />
624625
<Compile Include="QueryDsl\Specialized\Percolate\PercolateQueryUsageTests.cs" />
626+
<Compile Include="Reproduce\ConnectionReuseAndBalancing.cs" />
625627
<Compile Include="Reproduce\DateSerialization.cs" />
626628
<Compile Include="Reproduce\GithubIssue2152.cs" />
627629
<Compile Include="Reproduce\GithubIssue2306.cs" />
@@ -753,9 +755,7 @@
753755
<Content Include="ClientConcepts\LowLevel\pipeline.xml" />
754756
<Content Include="QueryDsl\BoolDsl\hadouken-indentation.jpg" />
755757
</ItemGroup>
756-
<ItemGroup>
757-
<Folder Include="ClientConcepts\Connection\" />
758-
</ItemGroup>
758+
<ItemGroup />
759759
<Import Project="..\outputpath.props" />
760760
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
761761
<Choose>

0 commit comments

Comments
 (0)