-
Notifications
You must be signed in to change notification settings - Fork 401
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
HTTP Client socket leak with default configuration manager #1078
Comments
That HttpClient is created once at startup. https://github.com/aspnet/AspNetCore/blob/436b5461ad0337aac90089aa7ccb61dd875808e4/src/Security/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerPostConfigureOptions.cs#L53 Are you doing anything interesting with AddJwtBearer? Do you have multiple? Do you add and remove them? Does BackchannelHttpHandler also mitigate your issue? |
@Tratcher yes I know it is - that's why I'm confused as to why injecting our own would make any difference. We're not doing anything special as far as I know. One thing that confused me a bit is that function within AddJwtBearer options seemed to be called on each api call - I wouldn't expect that, but I will double check if that is actually the case Below is our original code
and its setup in ConfigureServices via this:
|
@Tratcher Any comments on this? I can confirm that the Action within the JwtBearerOptions is called on every request. I'm not sure why this is the case. Also, I can't find any examples that use BackChannelHttpHandler but since using our own HTTP Client completely fixes the issue (stress testing fails at 2 req/sec using the code above to working with 40 req/sec with the code below) I'm at a loss to understand if it's something we're doing wrong or if there is an issue within the authentication stack. This code works fine:
|
The AddJwtBearer config lambda shouldn't be running every request unless your app is somehow restarting or you have something very wrong with DI. OnTokenValidated should run on every request that has a token. |
@Tratcher ok thanks for the pointers. I think we have something very wrong with DI - can you elaborate on that in any way? When I use the in-built DI everything works as expected, when I use the Unity DI (latest version 2.1.3) it exhibits the above behavior. I've no idea why Unity would cause this and I can't raise a bug report with them until I understand what is going on. How does DI impact the AddJwtBearer extension method? |
AddJwtBearer depends on several singleton DI services. If those aren't being treated as singletons by your container then your config will keep getting re-run and cause the issues you've seen. It may just be a usage issue rather than a bug in container itself. How do you have it wired up? There are examples for using most containers with AspNetCore. E.g. https://docs.microsoft.com/en-us/aspnet/core/migration/proper-to-2x/mvc2?view=aspnetcore-2.2#native-dependency-injection |
@Tratcher I'm using the package Unity.Microsoft.DependencyInjection described here https://github.com/unitycontainer/examples/tree/master/src/AspNetCoreExample that's meant to implement all the plumbing in the example you provide, |
@Tratcher I've had a look at the code for AddJwtBearer... the first singleton registration I can see is for IPostConfigureOptions.... unfortunately when I look at the known registrations within Unity on completion of starttup I can see this correctly registered as a Singleton... because this works, I'm assuming the rest are working too. There is an instance of JwtBearerOptions is marked as a Transient though... not sure if this is appropriate or not or where this comes from. Any other ideas? |
@HaoK do you have a good explanation for how a bad DI setup would cause auth options to get reset per request? |
So generally auth uses There's not too much going on, basically the monitor returns whatever is in the cache, if its a miss, it uses the factory to create a new instance. https://github.com/aspnet/Extensions/blob/master/src/Options/Options/src/OptionsMonitor.cs Where does the transient instance of jwtbearer come from? That's most likely the issue |
When reproducing this issue I see no Unity code involved at the moment:
So, the issue is with how it is created. If you could point me to that part in your code I could verify how is it different from native DI. |
@HaoK it looks like an issue with OptionsMonitor failing to cache, no? |
Between refresh request start and that line in the code few types are resolved from container. Types Unity resolves:
On the same page refresh these are the types native DI resolves:
|
Which of those are created fresh each resolve, and which return cached singletons? |
It should not matter. If these requests are consistently different with native DI it means execution path is different as well. So, either Unity does not comply with registration convention or native DI uses some kind of magic trick to create something. But to answer your question, neither one of these is singleton in Unity. |
I just cloned entire Extensions Repo, built sample with project references instead of nuget packages and tried to reproduce the error: I could not! I am assuming it was fixed in the later version and no longer a problem. @bunceg please update to the latest and verify. |
I will double check the later released versions tomorrow but hopefully it’s patched on the 2.1 LTS branch rather than the 2.2 branch.... |
@Tratcher @ENikS I've used the 2.1.7 package and the latest 2.2.1 Microsoft.AspNetCore.App package (with associated .net SDK) and the latest version of unity (5.9.1) None of these updates have fixed the problem. Since @ENikS did his test from source, is there an outstanding change that hasn't been packaged up yet and, if so, will it be available as a 2.1.8 release (due to 2.1.x being under LTS) ? |
If @ENikS built from source it was likely the master branch which is developing 3.0.0. You can try a nightly build at https://github.com/dotnet/core-sdk#installers-and-binaries We can't talk about patching until we track down what the cause and solution were. |
It was master branch. |
@Tratcher I'm a bit stuck here. I'm updating my test app to the latest NuGet Microsoft.AspNetCore.App version 3.0.0-preview-18579-0056 and it's failing to update. I've set TargetFramework to netcoreapp3.0 and installed the .NET SDK from the link you gave me (.NET Core SDK 3.0.100-preview) as below. VS (2017) won't build the solution with an error "the current .NET SDK does not support targeting .NET Core 3.0.... etc. command line dotnet build fails with errors below. So not sure where to go next to help you work out whether the issue is really fixed in 3.0 or not. |
You need Visual Studio 2019 |
I see.... a veritable hornets nest of installing of preview versions then.... @Tratcher is this something I need to pursue independently of the analysis @ENikS and I have already done? it's not a Unity issue, it is an issue in .net core 2.1 / 2.2 but (apparently) not in 3.0.. so it's directly pointing at a bug in .net core itself. I am surprised that this hasn't come up before but I presume the majority of use cases is to use the in-built DI |
If you want to pursue a patch then we still need to narrow down what the issue was and how it was fixed. That doesn't necessarily require installing the previews, that was more for confirmation of the fix. I see two options: 1) further debugging 2.x to figure out the original issue, or 2) diffing 2.x and 3.0 code to figure out what changed. At the very least this discussion should move to https://github.com/aspnet/aspnetcore since the issue seams to be in that code base. Can you open a new issue there and summarize the findings so far? |
@Tratcher ok done. I do want a patch pursued at this is causing us load issues on our platform, and we are locked to the 2.1 LTS branch for now. The only alternative appears to be to use in-built DI, which isn't really fair on Unity as apparently is not their fault, and causes us problems as we have a lot of custom wrapper code around unity around decorators etc. that we'd need to re-write to use custom DI. |
@brentschmaltz you can close this issue as a duplicate of dotnet/aspnetcore#7030. |
@Tratcher sure |
I think this is a leak issue with the default setup of AddJwtBearer.
We have setup our options with a MetadataAddress but not a configuration manager. Under load we get socket errors when trying to get the openid-configuration. Tracing the default code through, we get to HttpDocumentRetriever - this uses it's own HTTP Client (admittedly via static construction so it looks like it should only use one instance) but it's a suspicious candidate for our leak.
When we change the AddJwTBearer to use the default OpenIdConnectConfiguration and HttpDocumentRetrievver but with our own static instance of http client we don't get any socket exceptions.
Therefore it looks like HttpDocumentRetriever has a leak, but I can't really work out why from the code.
The text was updated successfully, but these errors were encountered: