Skip to content

Commit 3e3e30b

Browse files
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 44c5c84 commit 3e3e30b

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)