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

[Kestrel] Move to GenericHost #24279

Merged
13 commits merged into from
Aug 5, 2020
Merged

Conversation

Kahbazi
Copy link
Member

@Kahbazi Kahbazi commented Jul 24, 2020

Part of #20964

@ghost ghost added the area-servers label Jul 24, 2020
@Tratcher Tratcher requested a review from BrennanConroy July 24, 2020 16:24
@Kahbazi
Copy link
Member Author

Kahbazi commented Jul 27, 2020

I'm having a difficult time fixing the tests, I think the reason is the different implementation of Dispose method between Host and WebHost.
When WebHost is being disposed, it will also call StopAsync() which also stops the IServer,
but when Host is being disposed, it won't call StopAsync().
Is this behavior by design?
Am I on the right path?

@Tratcher
Copy link
Member

Yes, it's different because StopAsync was added to the host later. The tests should call StopAsync.

@Kahbazi
Copy link
Member Author

Kahbazi commented Jul 28, 2020

I still couldn't pass ServerShutsDownGracefullyWhenMaxRequestBufferSizeExceeded and GracefulTurnsAbortiveIfRequestsDoNotFinish. It looks like it hangs here until host Shutdown timeout.

return await Task.WhenAny(allAbortedTask, Task.Delay(1000)).ConfigureAwait(false) == allAbortedTask;

@BrennanConroy
Copy link
Member

Looks like a few tests are still failing because StopAsync isn't being called.

Copy link
Member

@BrennanConroy BrennanConroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the other test failure. Might have to take a closer look in a bit.

@@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
/// </summary>
internal class TestServer : IDisposable, IStartup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make TestServer implement IAsyncDisposable, so we can just change our usings to await usings. Even though IHost doesn't implement IAsyncDisposable, Host does so we can just cast.

Surprisingly, it doesn't look like disposing the Host actually stops it when it's running, but I haven't tested that. Not a big deal either way as we can always call Host.StopAsync() before calling Host.DispooseAsync() in TestServer.DisposeAsync().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I add Host.StopAsync() in TestServer.DisposeAsync()? Right now I call server.StopAsync() for every instance of TestServer before it is disposing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what we did in SignalR tests. It would clean up all the tests a little :D

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Time to revert some commits 😁 I'll remove the server.StopAsync from the tests.

})
.UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName)
.UseSetting(WebHostDefaults.ShutdownTimeoutKey, TestConstants.DefaultTimeout.TotalSeconds.ToString())
.Build();

_host.Start();
Copy link
Member

@halter73 halter73 Jul 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't have to be done for this PR, but long term I'd like to get rid of all calls to the IHost.Start() and IHost.Dispose() in our tests and instead use their async alternatives. This will mean moving away from using the TestServer constructor to give as an already-started TestServer. We might need to switch to an async TestServer factory method instead.

@BrennanConroy
Copy link
Member

Took a look at the ServerShutsDownGracefullyWhenMaxRequestBufferSizeExceeded test.

It looks like close is working the same as before, where the server shutdown is closing ungracefully because of the blocking app code, the only difference between WebHost and Host is that after the server shutdown there is a cancellation token check in Host which is causing the exception, in WebHost this check didn't exist.

https://github.com/dotnet/runtime/blob/df7f985f44712efd46b8b3bc5e4d83fe3d83ed4b/src/libraries/Microsoft.Extensions.Hosting/src/Internal/Host.cs#L91

the server shutdown is closing ungracefully

The test name seems to indicate there should be a graceful close, so either the test name isn't quite accurate, or the server code has changed since this test was made and there isn't really a check for graceful close in this test.

@Tratcher @halter73 Thoughts on this test? Should we just put a OperationCanceledException catch around Host.StopAsync, or maybe stop the server explicitly instead of the Host to verify it doesn't throw?

@halter73
Copy link
Member

halter73 commented Aug 3, 2020

Regarding ServerShutsDownGracefullyWhenMaxRequestBufferSizeExceeded. It's too bad we're just now noticing the difference in behavior for ungraceful shutdown with the generic Host.

Kestrel has always tried to treat the token being canceled during KesterlServer.StopAync() as gracefully as possible, since long running requests/connection that aren't listening to the stopping notification are not that uncommon. Kestrel writes a debug log, but that's it. It doesn't throw which would cause most apps to exit with an exception.

I think we might need to fix the runtime to just remove the call to token.ThrowIfCancellationRequested(). I'd consider this a regression since WebHost doesn't do this. Not only that, but that call to token.ThrowIfCancellationRequested() prevents the following call to _hostLifetime.StopAsync(token) from ever happening. Fortunately ConsoleLifetime.StopAsync(CancellationToken) currently doesn't do anything, but what if it did?

@halter73
Copy link
Member

halter73 commented Aug 3, 2020

Basically the semantics when passing a canceled token (or a token that becomes canceled) to KestrelServer.StopAsync has always been to do an abortive shutdown without throwing, but then generic host is treating a canceled token as indicating StopAsync can be completely skipped (at least for the IHostedLifetime) and StopAsync should throw. Generic host might be using the more common semantics for CancellationToken, but we need to be using Kestrel's semantics if we're going to use the CancellationToken to indicate shutdown should become abortive (rather than to indicate shutdown should be skipped) and I don't see any alternative this late before 5.0.

@Tratcher
Copy link
Member

Tratcher commented Aug 3, 2020

@halter73 lets talk after triage. People have been using Kestrel this way since 3.0, we shouldn't be changing the host's behavior now.

@ghost
Copy link

ghost commented Aug 5, 2020

Hello @BrennanConroy!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@BrennanConroy BrennanConroy added this to the 5.0.0-rc1 milestone Aug 5, 2020
@ghost ghost merged commit b2c7d51 into dotnet:master Aug 5, 2020
@Kahbazi Kahbazi deleted the kahbazi/KestrelHostBuilder branch August 5, 2020 21:50
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 6, 2023
This pull request was closed.
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants