Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Periodic socket exceptions #4

Open
dandenton opened this issue Sep 26, 2023 · 1 comment
Open

Periodic socket exceptions #4

dandenton opened this issue Sep 26, 2023 · 1 comment

Comments

@dandenton
Copy link

Hi, we're occationally getting errors while publishing health checks. Are we missing something with configuration or should the default ElmahioAPI.Create's HttpContext be using Polly or something similar to provide automatic retries for transient failures?

Exception: Health check "Elmah.Io.AspNetCore.HealthChecks.ElmahIoPublisher" threw an unhandled exception after 1.8186ms
Exception stack trace:

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.Security.SslStream.ReadAsyncInternal[TIOAdapter](Memory`1 buffer, CancellationToken cancellationToken)
   at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
   at System.Net.Http.HttpConnection.<CheckUsabilityOnScavenge>g__ReadAheadWithZeroByteReadAsync|44_0()
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.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 Elmah.Io.Client.HeartbeatsClient.CreateAsync(String id, String logId, CreateHeartbeat body, CancellationToken cancellationToken) in /_/src/Elmah.Io.Client/ElmahioClient.cs:line 802
   at Elmah.Io.AspNetCore.HealthChecks.ElmahIoPublisher.PublishAsync(HealthReport report, CancellationToken cancellationToken) in /_/src/Elmah.Io.AspNetCore.HealthChecks/ElmahIoPublisher.cs:line 79
   at Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckPublisherHostedService.RunPublisherAsync(IHealthCheckPublisher publisher, HealthReport report, CancellationToken cancellationToken)
   at Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckPublisherHostedService.RunAsyncCore(CancellationToken cancellationToken)
   at Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckPublisherHostedService.RunAsync()
@ThomasArdal
Copy link
Member

You shouldn't experience those kind of errors very often. It looks like either the elmah.io API isn't available or there's some kind of connection problem.

There are a couple of things you can do. First, I would increase the default timeout in the client used to create heartbeats:

var api = ElmahioAPI.Create("API_KEY", new ElmahIoOptions
{
    Timeout = new TimeSpan(0, 0, 30)
});

The default timeout is 5 seconds which should be fine in most cases. But increasing it for scenarios like this where no user is (typically) waiting for a reply is a good approach.

The elmah.io client does not implement retries itself. But setting up a retry with Polly is a good idea. You can provide your own HttpClient when creating the client:

var api = ElmahioAPI.Create("API_KEY", options, httpClient);

Setting up a retry can be done in multiple ways. I copied and adjusted some code from here:

builder.Services
    .AddHttpClient("elmahio")
    .AddPolicyHandler(HttpPolicyExtensions
        .HandleTransientHttpError()
        .WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(1)));

I hope that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants