.NET 6 Client Intermittent issue crashes client
- Dominant language
- C#
- Stars
- 4.5k
- Forks
- 836
- Avg merge
- 6d 3h
- Merged PRs (30d)
- 7
Description
I'm getting an intermittent error that is causing my one client to crash. This client is running as a background service calling the gRPC server using Parallel.ForEach. This client is also writing to request streams and subscribing to response streams.
Client Exception:
```
Grpc.Core.RpcException: Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. IOException: The request was aborted. IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.. SocketException: An existing connection was forcibly closed by the remote host.", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request.")
---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.IO.IOException: The request was aborted.
---> 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.GetResult(Int16 token)
at System.Net.Security.SslStream.EnsureFullTlsFrameAsync[TIOAdapter](TIOAdapter adapter)
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
at System.Net.Http.Http2Connection.ProcessIncomingFramesAsync()
--- End of inner exception stack trace ---
at System.Net.Http.Http2Connection.ThrowRequestAborted(Exception innerException)
at System.Net.Http.Http2Connection.Http2Stream.CheckResponseBodyState()
at System.Net.Http.Http2Connection.Http2Stream.TryEnsureHeaders()
at System.Net.Http.Http2Connection.Http2Stream.ReadResponseHeadersAsync(CancellationToken cancellationToken)
at System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.Http2Connection.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 Grpc.Net.Client.Balancer.Internal.BalancerHttpHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Grpc.Net.Client.Internal.GrpcCall`2.RunCall(HttpRequestMessage request, Nullable`1 timeout)
--- End of inner exception stack trace ---
at Grpc.Net.Client.Internal.GrpcCall`2.GetResponseHeadersCoreAsync()
```
Server code:
```
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel(options =>
{
options.Limits.Http2.MaxFrameSize = 16777215;
options.ListenAnyIP(portNumber, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps(httpsOptions =>
{
// get certificate
});
});
});
webBuilder.UseStartup();
});
```
Client Code:
```
private void BuildGrpcNetClientChannel()
{
var credentials = CallCredentials.FromInterceptor(AddTokenToHeaderAsync);
var channelOptions = new GrpcChannelOptions
{
MaxReceiveMessageSize = null,
MaxSendMessageSize = null,
HttpHandler = GetHttpMessageHandler(),
Credentials = ChannelCredentials.Create(ChannelCredentials.SecureSsl, credentials)
};
GrpcChannel = GrpcChannel.ForAddress($"https://{ServerAddress}:{ServerPort}", channelOptions);
}
private HttpMessageHandler GetHttpMessageHandler()
{
return new SocketsHttpHandler()
{
PooledConnectionIdleTimeout = TimeSpan.FromMinutes(1),
SslOptions = new SslClientAuthenticationOptions()
{
RemoteCertificateValidationCallback = (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
{
// cert validation
}
},
};
}
private async Task AddTokenToHeaderAsync(AuthInterceptorContext context, Metadata metadata)
{
if (!string.IsNullOrEmpty(_token))
{
try
{
await _semaphore.WaitAsync(context.CancellationToken);
if (DateTime.UtcNow >= _tokenExpiration)
{
// call to server to refresh token
_token = await RefreshTokensAsync(context.CancellationToken);
}
metadata.Add("Authorization", $"Bearer {_token}");
}
catch (OperationCanceledException)
{
// do nothing
}
catch (Exception ex)
{
log.Fatal(ex.ToString());
}
finally
{
_semaphore.Release();
}
}
}
```
Any help would be appreciated. Every time I think I fix it, the problem shows up in a few weeks.
Contributor guide
Assessment
This issue has not been assessed yet.