-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Microsoft.Extensions.Http.Polly: Deadlock when retrying a "503 - Service unavailable" #28384
Comments
I ve also tryied using the latest package versions (3.1.6) and the problem persists |
The problem also reproduces for Can this be escalated somehow? A week passed and I did not get any valuable feedback yet :) |
I managed to progress in finding the cause of the issue: the connections to the remote server aren't closing; for each retry a new connection is created and the reason the application hangs on the second retry is due to the Increasing So back to almost square 1. Further google ing the problem I found a post suggesting to abort the underlying HttpWebRequest. Oddly enough, the disposal is not needed for the second scenario (Observation no 2), where there is no additional So the big unanswered question here is: Why/how is the additional |
@marcpaulv I am personally curious about this issue, can you share your reproduce code that is used for MaxConnectionsPerServer example? |
private static string urlString = "http://123123123"; // replace this with your own
async static Task Main(string[] args)
{
ServicePoint sp = ServicePointManager.FindServicePoint(new Uri(urlString));
IServiceCollection services = new ServiceCollection();
services.AddHttpClient("test")
// comment out the below policy for a correct behavior
.AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(4),
}, onRetry: (response, timespan) =>
{
Console.WriteLine($"Retry: {timespan}, HttpStatusCode={response?.Result.StatusCode},ServicePoint={sp.GetHashCode()} Connections={sp.CurrentConnections}");
// uncomment below for workaround to issue
//Console.WriteLine("DIsposing HttpresponseMessage");
//response?.Result.Dispose();
}))
.ConfigurePrimaryHttpMessageHandler(_ =>
{
Console.WriteLine($"Setting MaxConnectionsPerServer to 10");
var h = new HttpClientHandler
{
MaxConnectionsPerServer = 10,
};
return h;
});
// removing the logging handlers as a work around for https://github.com/aspnet/Extensions/issues/563
ServiceDescriptor loggingHandler = services.FirstOrDefault(e => e.ServiceType == typeof(IHttpMessageHandlerBuilderFilter));
if (loggingHandler != null)
{
services.Remove(loggingHandler);
}
IHttpClientFactory factory = services.BuildServiceProvider().GetService<IHttpClientFactory>();
HttpClient client = factory.CreateClient("test");
Console.WriteLine("Created client");
while (true)
{
Console.WriteLine($"Sending request");
HttpResponseMessage response = null;
try
{
response = await client.GetAsync(urlString).ConfigureAwait(false);
Console.WriteLine($"HttpStatusCode={response?.StatusCode}, Connections={sp.CurrentConnections}");
}
catch (Exception e)
{
Console.WriteLine($"Error={e.Message}, Connections={sp.CurrentConnections}");
}
Thread.Sleep(1000);
}
} |
I would like to add myself to this issue as we are experiencing the same issue, but from an entirely different direction. I will try it out with the httpMessageResponse.Dispose() to see if that eliminates the problem, but would rather help in resolving the issue. For this I created a self contained testing solution, it can be found here: https://github.com/Dragonsangel/PollyConnectionsRemainOpen |
When you're working with HttpClient it buffers all responses by default (HttpContent.LoadIntoBufferAsync) and this frees up the underlying connection for the next request. However, when you're working inside the HttpClient with a DelegatingHandler then all responses are in a streaming state and if you don't drain or dispose that stream then you leak an active connection. |
Thanks for contacting us. |
Notes:
|
@Tratcher Nice find. Dylan's been away from Polly for a while (App-vNext/Polly#798) and isn't getting GitHub notifications. Feel free to ping me if anything Polly-related pops up in the future, and I'll see if I can help out. |
Thanks Martin, what do you think of the fix? |
I had a look and it seemed reasonable to me. I'd maybe have been 60:40 as to whether I'd have used |
Description:
When the Application Pool of an IIS hosted website stops for whatever reason (in my case i stopped it manually), IIS returns a 503 - Service unavailable status code and adds a Connection: close response header.
When retrying such a request with the retry policies (the below is with
WaitAndRetryAsync
), the first 2 retries are returning the same status (503) but the third retry is causing the application to stop responding (most probably a deadlock happens).Steps to reproduce
Expected behavior
The application should start receiving 200 OK responses.
Actual behaviour
The application hangs after the first 2 retries of the first 503 Service unavailable response.
Note that if the
WaitAndRetryAsync
policy addition is commented out, the application behaves as expected (without the retries of course).Code to reproduce the problem
Observations
ExecutyPolicyAsync
(with the.AddTransientHttpErrorPolicy
commented out) is working as expected:The text was updated successfully, but these errors were encountered: