Skip to content

Automatic retry on IOException/SocketException #266

@bill-poole

Description

@bill-poole

The default/configurable retry strategies do not seem to support retries on an IOException. However, the AWS SDK does consider an IOException to be transient under some conditions. I find that occasionally I receive an IOException caused by an underlying SocketException with error code 10054 (ConnectionReset), which means "an existing connection was forcibly closed by the remote host."

The AWS .NET SDK logic pertaining to retrying on IOException is (from RetryPolicy.cs):

// An IOException was thrown by the underlying http client.
// FileNotFoundException is not considered a transient error because
// we don't consider local .NET assembly file changes to be happening.
// If a FileNotFoundException happens there is most likey a bad install
// of the SDK or .NET assembly binding issue.
if (exception is IOException && exception is not FileNotFoundException)
{

#if !NETSTANDARD  // ThreadAbortException is not NetStandard

    // Don't retry IOExceptions that are caused by a ThreadAbortException
    if (ExceptionUtils.IsInnerException<ThreadAbortException>(exception))
        return false;

#endif
    // Retry all other IOExceptions
    return true;
}
else if (ExceptionUtils.IsInnerException<IOException>(exception))
{
    return true;
}       

It would be very useful if this library would allow configuration of and provide a default for a retry policy for these transient exceptions.

The relevant excerpt of my stack trace is:

System.Net.Http.HttpRequestException: An error occurred while sending the request.
       ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
       ---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
         --- End of inner exception stack trace ---
         at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
         at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
         at System.Net.Http.HttpConnection.InitialFillAsync(Boolean async)
         at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         --- End of inner exception stack trace ---
         at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
         at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.DecompressionHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
         at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
         at EfficientDynamoDb.Internal.HttpApi.SendAsync(DynamoDbContextConfig config, HttpContent httpContent, CancellationToken cancellationToken)
         at EfficientDynamoDb.DynamoDbContext.GetItemAsync[TEntity](DdbClassInfo classInfo, BuilderNode node, CancellationToken cancellationToken)
         at EfficientDynamoDb.Operations.GetItem.GetItemEntityRequestBuilder`1.ToItemAsync(CancellationToken cancellationToken)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions