This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 27b60a58a4 IGNITE-20832 .NET: Improve retry mechanism (#2842)
27b60a58a4 is described below
commit 27b60a58a4c993a2379baabb273e98e1f770b453
Author: Pavel Tupitsyn <[email protected]>
AuthorDate: Thu Nov 16 16:07:05 2023 +0200
IGNITE-20832 .NET: Improve retry mechanism (#2842)
`TestDroppedConnectionIsRestoredOnDemand` was flaky because in some cases
we failed to retry a broken connection error.
* Close client socket immediately on write error
* Improve `ShouldRetry` logic
---
.../dotnet/Apache.Ignite.Tests/ReconnectTests.cs | 7 ++++++-
.../Apache.Ignite/Internal/ClientFailoverSocket.cs | 9 +++++++--
.../dotnet/Apache.Ignite/Internal/ClientSocket.cs | 16 +++++++++++++++-
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/ReconnectTests.cs
b/modules/platforms/dotnet/Apache.Ignite.Tests/ReconnectTests.cs
index 695377ded0..60767f09fd 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/ReconnectTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/ReconnectTests.cs
@@ -70,8 +70,13 @@ public class ReconnectTests
[Test]
public async Task TestDroppedConnectionIsRestoredOnDemand()
{
+ var cfg = new IgniteClientConfiguration
+ {
+ Logger = new ConsoleLogger { MinLevel = LogLevel.Debug }
+ };
+
using var server = new FakeServer();
- using var client = await server.ConnectClientAsync();
+ using var client = await server.ConnectClientAsync(cfg);
Assert.DoesNotThrowAsync(async () => await
client.Tables.GetTablesAsync());
diff --git
a/modules/platforms/dotnet/Apache.Ignite/Internal/ClientFailoverSocket.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/ClientFailoverSocket.cs
index 172bf4a1c8..74a5016bcb 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/ClientFailoverSocket.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/ClientFailoverSocket.cs
@@ -555,14 +555,14 @@ namespace Apache.Ignite.Internal
{
var e = exception;
- while (e != null && !(e is SocketException))
+ while (e != null && !IsConnectionError(e))
{
e = e.InnerException;
}
if (e == null)
{
- // Only retry socket exceptions.
+ // Only retry connection errors.
return false;
}
@@ -582,6 +582,11 @@ namespace Apache.Ignite.Internal
var ctx = new RetryPolicyContext(new(Configuration),
publicOpType.Value, attempt, exception);
return retryPolicy.ShouldRetry(ctx);
+
+ static bool IsConnectionError(Exception e) =>
+ e is SocketException
+ or IOException
+ or IgniteClientConnectionException { Code:
ErrorGroups.Client.Connection };
}
/// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/ClientSocket.cs
b/modules/platforms/dotnet/Apache.Ignite/Internal/ClientSocket.cs
index a0801138b0..dc24fcc5da 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/ClientSocket.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/ClientSocket.cs
@@ -496,7 +496,7 @@ namespace Apache.Ignite.Internal
{
// Disconnected.
throw new IgniteClientConnectionException(
- ErrorGroups.Client.Protocol,
+ ErrorGroups.Client.Connection,
"Connection lost (failed to read data from socket)",
new SocketException((int)
SocketError.ConnectionAborted));
}
@@ -617,6 +617,10 @@ namespace Apache.Ignite.Internal
sslStream.SslProtocol)
: null;
+ [SuppressMessage(
+ "Microsoft.Design",
+ "CA1031:DoNotCatchGeneralExceptionTypes",
+ Justification = "Any exception during socket write should be
handled to close the socket.")]
private async ValueTask SendRequestAsync(PooledArrayBuffer? request,
ClientOp op, long requestId)
{
// Reset heartbeat timer - don't sent heartbeats when connection
is active anyway.
@@ -664,6 +668,16 @@ namespace Apache.Ignite.Internal
Metrics.RequestsSent.Add(1);
}
+ catch (Exception e)
+ {
+ var message = "Exception while writing to socket, connection
closed: " + e.Message;
+
+ _logger?.Error(e, message);
+ var connEx = new
IgniteClientConnectionException(ErrorGroups.Client.Connection, message, new
SocketException());
+
+ Dispose(connEx);
+ throw connEx;
+ }
finally
{
_sendLock.Release();