-
Notifications
You must be signed in to change notification settings - Fork 71
Getting a endless HttpMessageHandler cleanup cycle #165
Comments
From @rynowak on Tuesday, 28 August 2018 18:00:02 This means that there's a client/message handler that's been expired, but someone is still holding a reference to it. You can analyze what's keeping it alive by capturing a memory dump. |
I'm experiencing the same issue, in the memory dump I don't see any HttpClient kept alive. Any other pointers on where to look? |
After further investigation, the following object are incremented on each call to my web service:
I am using a custom asp.net core middleware that on each call uses IServiceProvider to create an instance of a request handler, which uses IHttpClientFactory to create an HttpClient. |
If you're looking at a memory dump you should be able to find the "path to root" of one of these objects - that will show you what's keeping it around in memory. What's the "path to root" of |
The path to root is: |
Is there an instance of |
It would be great to see the path to root of |
Doesn't seem to be.
HttpClientHandler -> LoggingHttpMessageHandler -> LoggingScopeHttpMessageHandler -> ExpiredHandlerTrackingEntry -> DefaultHttpClientFactory -> Dictionary<object, object> -> ServiceProviderEngineScope -> KestrelServerOptions -> Http1Connection -> AsyncTaskMethodBuilder... -> Dictionary<Int32, Task> |
When you're collecting these logs is your application mostly idle? Everything you've shown me so far seems to indicate that things are working correctly, but the weakreference hasn't been killed yet.
Once |
My app is completely idle, it has finished handling the requests. Do you have any ideas why is |
It seems this is the expected behavior, as it happens with an empty app that just uses |
Or maybe this has to do with the underlying connection handling by kestrel? |
Kestrel handles sever resources not client resources (incoming connections not outgoing connections) |
yes, I meant that maybe the connection that generated the request is still alive, even though my app finished handling the request |
@mixandmatch025 what does your application look like? Can you share a sample that reproduces the problem? |
Just a simple app can reproduce what I'm refering to: class Program
{
static async Task Main(string[] args)
{
var host = WebHost.CreateDefaultBuilder()
.ConfigureLogging(l => l.SetMinimumLevel(LogLevel.Debug))
.ConfigureServices(s => s.AddHttpClient("default").SetHandlerLifetime(TimeSpan.FromSeconds(1)))
.Configure(a => a.Run(c =>
{
var client = c.RequestServices.GetService<IHttpClientFactory>().CreateClient("default");
return Task.CompletedTask;
}))
.Build();
await host.RunAsync();
}
} the |
Thanks, I'll try to reproduce this. |
Yep, I can reproduce it... |
The WeakReference is isn't null and is pointing to a
|
OK, well if it is the timer callback capturing it that's great because then we understand the issue. |
Hmm I'm not sure there's a leak, in my console app repro, things are cleaned when I force a GC. |
I think things are working as expected. |
OK after some investigation everything here is by design. Here's what's happening:
The logs seem indicate that things are never going out of scope and hence the supposed leak. What's happening is the timer that is used to expire the handler has a reference to a callback which seemingly keeps the HttpMessageHandler alive. When a GC happens things are cleaned up as expected. Until then, the background scanner will keep looping until that happens. If anything we could look at changing how we scan to avoid spamming the logs in this situation. |
Thank @davidfowl and @rynowak for the details! Very good to know! Indeed after a long while it seems to have "process them". Avoiding spamming the logs is indeed a good first step, but could this also hide real leaks? Any idea when this could be optimized? thank you, |
We log this at debug level on purpose because we don't want to spam you, but we want a way to figure out what's happening if you're curious. |
Great! I like this answer ;o) |
If anything it can point out real leaks. If you're holding onto |
@davidfowl @rynowak thanks for clearing things up. |
@mixandmatch025 thanks for sticking with us. For now this seems relatively harmless, the underlying issue (timer capturing the service provider) will go away in 2.2.0-preview3 |
From @masterjs on Tuesday, 28 August 2018 14:21:50
Hello,
I'm using the HTTP Client factory for ASPNETCORE 2.1. But now, after my second http request, I'm starting to get some logs that are getting me worried.
HttpMessageHandler expired after 120000ms for client 'default'
Starting HttpMessageHandler cleanup cycle with 1 items
BDC.ClientPortal.ApiManager> [10:11:49 DBG] Ending HttpMessageHandler cleanup cycle after 0.0342ms - processed: 0 items - remaining: 1 items
BDC.ClientPortal.ApiManager> [10:11:59 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
BDC.ClientPortal.ApiManager> [10:11:59 DBG] Ending HttpMessageHandler cleanup cycle after 0.0149ms - processed: 0 items - remaining: 1 items
BDC.ClientPortal.ApiManager> [10:12:09 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
BDC.ClientPortal.ApiManager> [10:12:09 DBG] Ending HttpMessageHandler cleanup cycle after 0.0025ms - processed: 0 items - remaining: 1 items
BDC.ClientPortal.ApiManager> [10:12:19 DBG] Starting HttpMessageHandler cleanup cycle with 1 items
BDC.ClientPortal.ApiManager> [10:12:19 DBG] Ending HttpMessageHandler cleanup cycle after 0.0017ms - processed: 0 items - remaining: 1 items ...
These logs are endless. Is that normal? (doesn't look normal)
thank you,
JS
***** dotnet --info *****
.NET Core SDK (reflecting any global.json):
Version: 2.1.400
Commit: 8642e60a0f
Runtime Environment:
OS Name: Windows
OS Version: 10.0.14393
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.1.400\
Host (useful for support):
Version: 2.1.2
Commit: 811c3ce6c0
.NET Core SDKs installed:
1.1.0 [C:\Program Files\dotnet\sdk]
1.1.4 [C:\Program Files\dotnet\sdk]
...
2.1.202 [C:\Program Files\dotnet\sdk]
2.1.400 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 1.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 1.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
....
Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Copied from original issue: dotnet/aspnetcore#3470
The text was updated successfully, but these errors were encountered: