Skip to content

Commit 1821016

Browse files
authored
Refine product check behaviour (#5913)
* Rework transient errors * Update tests * Update docs * Cleanup * Hide ProductCheckStatus on implementations * Further cleanup during testing * Reset scratch pad * Fix comments * Ensure we raise product check error as neccesary This ensures that if the consumer catches the exception and reuses the client which has previously failed the check, the failure exception is raised. * Update bulk all test which now fails due to product check
1 parent 5758b13 commit 1821016

File tree

17 files changed

+274
-164
lines changed

17 files changed

+274
-164
lines changed

docs/client-concepts/connection-pooling/exceptions/unrecoverable-exceptions.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ foreach (var failure in failures)
5858
case PipelineFailure.MaxRetriesReached:
5959
case PipelineFailure.Unexpected:
6060
case PipelineFailure.NoNodesAttempted:
61+
case PipelineFailure.FailedProductCheck:
6162
var unrecoverable = new PipelineException(failure);
6263
unrecoverable.Recoverable.Should().BeFalse(failure.GetStringValue());
6364
break;

docs/client-concepts/connection-pooling/product-checking/product-check-at-startup.asciidoc

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ please modify the original csharp file found at the link and submit the PR with
1818
Since v7.14.0, the client performs a required product check before the first call.
1919
This pre-flight product check allows the client to establish the version of Elasticsearch that it is communicating with.
2020

21-
The product check requires one additional HTTP request to be sent to the server as part of the request pipeline before
22-
the main API call is sent. In most cases, this will succeed during the very first API call that the client sends.
21+
The product check generally requires a single additional HTTP request to be sent to the server as part of the request pipeline before
22+
the first API call is sent. In most cases, this will succeed during the first API call that the client sends.
2323
Once the product check succeeds, no further product check HTTP requests are sent for subsequent API calls.
2424

2525
[source,csharp]
2626
----
2727
var audit = new Auditor(() => VirtualClusterWith
2828
.Nodes(1)
29+
.ProductCheck(r => r.SucceedAlways())
2930
.ClientCalls(r => r.SucceedAlways())
3031
.StaticConnectionPool()
3132
.Settings(s => s.DisablePing())
@@ -52,7 +53,7 @@ Here's an example with a single node cluster which fails for some reason during
5253
----
5354
var audit = new Auditor(() => VirtualClusterWith
5455
.Nodes(1, productCheckAlwaysSucceeds: false)
55-
.ProductCheck(r => r.Fails(TimesHelper.Once))
56+
.ProductCheck(r => r.Fails(TimesHelper.Once, 429))
5657
.ProductCheck(r => r.SucceedAlways())
5758
.ClientCalls(r => r.SucceedAlways())
5859
.StaticConnectionPool()
@@ -62,31 +63,30 @@ var audit = new Auditor(() => VirtualClusterWith
6263
audit = await audit.TraceCalls(skipProductCheck: false,
6364
new ClientCall() {
6465
{ ProductCheckOnStartup },
65-
{ ProductCheckFailure, 9200 }, <1>
66-
{ HealthyResponse, 9200 } <2>
66+
{ ProductCheckFailure, 9200 } <1>
6767
},
6868
new ClientCall() {
6969
{ ProductCheckOnStartup },
70-
{ ProductCheckSuccess, 9200 }, <3>
71-
{ HealthyResponse, 9200 }
70+
{ ProductCheckSuccess, 9200 }, <2>
71+
{ HealthyResponse, 9200 } <3>
7272
},
7373
new ClientCall() {
7474
{ HealthyResponse, 9200 } <4>
7575
}
7676
);
7777
----
78-
<1> as this is the first call, the product check is executed, but fails
79-
<2> the actual request is still sent and succeeds
80-
<3> as the previous product check failed, it runs again on the second call
78+
<1> as this is the first call, the product check is executed, but times out
79+
<2> as the previous product check failed, it runs again on the second call and this time it succeeds
80+
<3> this time the main API call is sent and also succeeds
8181
<4> subsequent calls no longer perform product check
8282

83-
Here's an example with a three node cluster which fails for some reason during the first and second product check attempts.
83+
Here's an example with a three node cluster which fails (due to too many requests) during the first and second product check attempts.
8484

8585
[source,csharp]
8686
----
8787
var audit = new Auditor(() => VirtualClusterWith
8888
.Nodes(3, productCheckAlwaysSucceeds: false)
89-
.ProductCheck(r => r.FailAlways())
89+
.ProductCheck(r => r.FailAlways(429))
9090
.ProductCheck(r => r.OnPort(9202).SucceedAlways())
9191
.ClientCalls(r => r.SucceedAlways())
9292
.StaticConnectionPool()

src/Elasticsearch.Net/ConnectionPool/SingleNodeConnectionPool.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@ public SingleNodeConnectionPool(Uri uri, IDateTimeProvider dateTimeProvider = nu
2727
/// <inheritdoc />
2828
public IReadOnlyCollection<Node> Nodes { get; }
2929

30-
/// <inheritdoc />
31-
public ProductCheckStatus ProductCheckStatus { get; set; } = ProductCheckStatus.NotChecked;
32-
3330
/// <inheritdoc />
3431
public bool SniffedOnStartup
3532
{
@@ -46,6 +43,9 @@ public bool SniffedOnStartup
4643
/// <inheritdoc />
4744
public bool UsingSsl { get; }
4845

46+
/// <inheritdoc />
47+
ProductCheckStatus IConnectionPool.ProductCheckStatus { get; set; } = ProductCheckStatus.NotChecked;
48+
4949
/// <inheritdoc />
5050
public IEnumerable<Node> CreateView(Action<AuditEvent, Node> audit = null) => Nodes;
5151

src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,6 @@ protected StaticConnectionPool(IEnumerable<Node> nodes, Func<Node, float> nodeSc
4848
/// <inheritdoc />
4949
public virtual IReadOnlyCollection<Node> Nodes => InternalNodes;
5050

51-
/// <inheritdoc />
52-
public ProductCheckStatus ProductCheckStatus { get; set; } = ProductCheckStatus.NotChecked;
53-
5451
/// <inheritdoc />
5552
public bool SniffedOnStartup { get; set; }
5653

@@ -80,6 +77,9 @@ protected List<Node> AliveNodes
8077
protected Random Random { get; }
8178
protected bool Randomize { get; }
8279

80+
/// <inheritdoc />
81+
ProductCheckStatus IConnectionPool.ProductCheckStatus { get; set; } = ProductCheckStatus.NotChecked;
82+
8383
/// <summary>
8484
/// Creates a view of all the live nodes with changing starting positions that wraps over on each call
8585
/// e.g Thread A might get 1,2,3,4,5 and thread B will get 2,3,4,5,1.

src/Elasticsearch.Net/Transport/Pipeline/InvalidProductException.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ namespace Elasticsearch.Net
88
{
99
public class InvalidProductException : Exception
1010
{
11-
public InvalidProductException()
12-
: base(@"The client noticed that the server is not Elasticsearch and we do not support this unknown product.") { }
11+
internal const string InvalidProductError = "The client noticed that the server is not Elasticsearch and we do not support this unknown product.";
12+
internal const string InvalidBuildFlavorError = "The client noticed that the server is not a supported distribution of Elasticsearch.";
13+
14+
public InvalidProductException(string error)
15+
: base(error) { }
1316
}
1417
}

src/Elasticsearch.Net/Transport/Pipeline/PipelineException.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public PipelineException(PipelineFailure failure, Exception innerException)
1919

2020
public bool Recoverable =>
2121
FailureReason is PipelineFailure.BadRequest or PipelineFailure.BadResponse or PipelineFailure.PingFailure;
22-
22+
2323
public IElasticsearchResponse Response { get; internal set; }
2424

2525
private static string GetMessage(PipelineFailure failure)
@@ -37,6 +37,8 @@ private static string GetMessage(PipelineFailure failure)
3737
case PipelineFailure.MaxRetriesReached: return "The call was retried the configured maximum amount of times";
3838
case PipelineFailure.NoNodesAttempted:
3939
return "No nodes were attempted, this can happen when a node predicate does not match any nodes";
40+
case PipelineFailure.FailedProductCheck:
41+
return RequestPipeline.ProductCheckTransientErrorWarning;
4042
case PipelineFailure.Unexpected:
4143
default:
4244
return "An unexpected error occurred. Try checking the original exception for more information.";

src/Elasticsearch.Net/Transport/Pipeline/PipelineFailure.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public enum PipelineFailure
1515
MaxRetriesReached,
1616
Unexpected,
1717
BadRequest,
18-
NoNodesAttempted
18+
NoNodesAttempted,
19+
FailedProductCheck
1920
}
2021
}

src/Elasticsearch.Net/Transport/Pipeline/ProductCheckStatus.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public enum ProductCheckStatus
1313
ValidProduct,
1414
InvalidProduct,
1515
UndeterminedProduct,
16-
TransientFailure
16+
TransientFailure,
17+
UnsupportedBuildFlavor
1718
}
1819
}

0 commit comments

Comments
 (0)