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

Remove blocking APIs in asp.net core integration tests code #43353

Open
1 task done
gdoron opened this issue Aug 17, 2022 · 14 comments
Open
1 task done

Remove blocking APIs in asp.net core integration tests code #43353

gdoron opened this issue Aug 17, 2022 · 14 comments
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions bug This issue describes a behavior which is not expected - a bug. help candidate Indicates that the issues may be a good fit for community to help with. Requires work from eng. team

Comments

@gdoron
Copy link

gdoron commented Aug 17, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Even on our very powerful Macbook pros, when we are running one of our integration test projects that has hundreds of tests, many of which use WebApplicationFactory we often get into deadlocks.

We set xunit to use unlimited amount of threads (-1), we have overridden a bunch of xunit stuff to implement a semaphore to limit the number of concurrent tests.
And yet, often we get into deadlocks after the ~600 tests completed mark.
After verifying we have no sync-over-async, we found this beauty in asp.net core code itself...
image

https://github.com/dotnet/aspnetcore/blob/main/src/Hosting/TestHost/src/TestServer.cs#L101
As well as this: https://github.com/dotnet/runtime/blob/2be87c9c976c0cd21b66ea12ae406a559aacaac0/src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/HostingAbstractionsHostExtensions.cs#L19

later on when we managed to reproduce the deadlock (after a very high number of attempts).
image

Bear in mind, xUnit which is by far the number 1 testing framework for .NET Core has SynchronizationContexts, even if this issue would be solved, there is still the MaxConcurrencySyncContext which I can only assume would still be used by default.

Can we please remove the sync over async anti pattern from our beloved framework?

Best,
Doron

@Tratcher
Copy link
Member

That TestServer constructor is no longer necessary, it was replaced by the following and only remains for back-compat, we could consider obsoleting it.

public static IWebHostBuilder UseTestServer(this IWebHostBuilder builder)

That Start extension method is also not necessary, it's only there for convenience. In a normal app it would only be called once and would be harmless. I agree it is a bit of a trap though.

@gdoron
Copy link
Author

gdoron commented Aug 17, 2022

@Tratcher I'm not sure I understand.
We are not talking about normal app, we are talking about tests project, that runs multiple tests in parallel, each with its own TestServer. So it's not harmless at all.
I probably did not understand what you meant.

@Tratcher
Copy link
Member

I meant it's harmless when the app is run in a development or production environment where there's only one instance per process. I see how it's problematic in a parallel test environment with many instances.

@adityamandaleeka
Copy link
Member

Triage: we could do a bunch of ConfigureAwait(false) on these things.

@adityamandaleeka adityamandaleeka added this to the .NET 8 Planning milestone Aug 19, 2022
@gdoron
Copy link
Author

gdoron commented Aug 20, 2022

@adityamandaleeka no way of making it truly async?
Is the best possible a blocking ConfigureAwait(false)?

@Tratcher
Copy link
Member

@gdoron async versions of these APIs already exist. The only thing we can change here is discouraging people from using the old sync ones.

@gdoron
Copy link
Author

gdoron commented Aug 22, 2022

@Tratcher how can one use the async versions when using \ deriving from WebApplicationFactory?
https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0#customize-webapplicationfactory

@Tratcher
Copy link
Member

Fair point, I hadn't reviewed WebApplicationFactory.

This usage looks async safe:

webHostBuilder.UseTestServer();

This one looks unsafe, CreateHost should be async:

@Tratcher Tratcher added the bug This issue describes a behavior which is not expected - a bug. label Aug 22, 2022
@gdoron
Copy link
Author

gdoron commented Dec 2, 2022

@Tratcher any chance having this sorted for 8.0 or even a minor version of 7?

@Tratcher
Copy link
Member

Tratcher commented Dec 2, 2022

Yes, we plan to look at it in 8. If you want to try fixing it that would be helpful.

@gdoron
Copy link
Author

gdoron commented Jul 16, 2023

@Tratcher just making sure this was not forgotten.
These deadlocks are a huge PITA for us for over a year now.
(Unfortunately I'm not knowledgeable enough to fix it myself 😞)

@Tratcher Tratcher added the help wanted Up for grabs. We would accept a PR to help resolve this issue label Jul 17, 2023
@Tratcher Tratcher self-assigned this Jul 17, 2023
@spaasis
Copy link

spaasis commented Jul 27, 2023

Possible workaround mentioned here https://www.strathweb.com/2021/05/the-curious-case-of-asp-net-core-integration-test-deadlock/

Subclass WebApplicationFactory:

private class AsyncFriendlyWebApplicationFactory<T> : WebApplicationFactory<T> where T : class
{
    protected override IHost CreateHost(IHostBuilder builder)
    {
        var host = builder.Build();
        Task.Run(() => host.StartAsync()).GetAwaiter().GetResult();
        return host;
    }
}

@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Aug 25, 2023
@Tratcher Tratcher removed their assignment Oct 2, 2023
@mkArtakMSFT mkArtakMSFT added help candidate Indicates that the issues may be a good fit for community to help with. Requires work from eng. team and removed help wanted Up for grabs. We would accept a PR to help resolve this issue labels Oct 28, 2023
@amcasey amcasey modified the milestones: .NET 8 Planning, Backlog Feb 14, 2024
@ardalis
Copy link
Contributor

ardalis commented Jul 2, 2024

This would still be a huge improvement to integration tests, especially those that use async methods to seed data. Ideally we would add a CreateHostAsync method that returns Task<IHost> and would thus allow us to await any method we needed to within that method.

@amcasey amcasey removed this from the Backlog milestone Jul 8, 2024
@amcasey amcasey added this to the .NET 10 Planning milestone Jul 8, 2024
@amcasey
Copy link
Member

amcasey commented Jul 8, 2024

@ardalis I doubt we'll be able to get to it in 9.0, but I've flagged it for review in 10.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions bug This issue describes a behavior which is not expected - a bug. help candidate Indicates that the issues may be a good fit for community to help with. Requires work from eng. team
Projects
None yet
Development

No branches or pull requests

8 participants
@adityamandaleeka @ardalis @Tratcher @gdoron @amcasey @spaasis @mkArtakMSFT and others