diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
index 8b00e14e6a..85c8dcc2e1 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
@@ -79,12 +79,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
}
}
- ///
- /// The amount of time to wait for active requests to drain while the server is shutting down.
- /// New requests will receive a 503 response in this time period. The default is 5 seconds.
- ///
- public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5);
-
internal void SetRequestQueueLimit(RequestQueue requestQueue)
{
_requestQueue = requestQueue;
diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs
index 01b8d831e8..e8aa2cca59 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs
@@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
private bool _stopping;
private int _outstandingRequests;
- private ManualResetEvent _shutdownSignal;
+ private TaskCompletionSource _shutdownSignal;
private readonly ServerAddressesFeature _serverAddresses;
@@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
_processRequest = new Action(ProcessRequestAsync);
_maxAccepts = _options.MaxAccepts;
EnableResponseCaching = _options.EnableResponseCaching;
- _shutdownSignal = new ManualResetEvent(false);
+ _shutdownSignal = new TaskCompletionSource();
}
internal HttpSysListener Listener { get; }
@@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public IFeatureCollection Features { get; }
- public void Start(IHttpApplication application)
+ public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
@@ -124,6 +124,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Listener.Start();
ActivateRequestProcessingLimits();
+
+ return Task.CompletedTask;
}
private void ActivateRequestProcessingLimits()
@@ -224,7 +226,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{
if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping)
{
- _shutdownSignal.Set();
+ LogHelper.LogInfo(_logger, "All requests drained.");
+ _shutdownSignal.TrySetResult(0);
}
}
}
@@ -242,24 +245,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys
context.Dispose();
}
- public void Dispose()
+ public Task StopAsync(CancellationToken cancellationToken)
{
_stopping = true;
// Wait for active requests to drain
if (_outstandingRequests > 0)
{
LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain.");
- var drained = _shutdownSignal.WaitOne(Listener.Options.ShutdownTimeout);
- if (drained)
- {
- LogHelper.LogInfo(_logger, "All requests drained successfully.");
- }
- else
+
+ var waitForStop = new TaskCompletionSource();
+ cancellationToken.Register(() =>
{
LogHelper.LogInfo(_logger, "Timed out, terminating " + _outstandingRequests + " request(s).");
- }
+ waitForStop.TrySetResult(0);
+ });
+
+ return Task.WhenAny(_shutdownSignal.Task, waitForStop.Task);
}
- // All requests are finished
+
+ return Task.CompletedTask;
+ }
+
+ public void Dispose()
+ {
+ _stopping = true;
Listener.Dispose();
}
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs
index 48913a746f..2bcd69e8c9 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
+using System.Threading;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
@@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
serverAddressesFeature.PreferHostingUrls = true;
server.Listener.Options.UrlPrefixes.Add(serverAddress);
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single());
}
@@ -46,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
serverAddressesFeature.Addresses.Add(overrideAddress);
server.Listener.Options.UrlPrefixes.Add(serverAddress);
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single());
}
@@ -63,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
serverAddressesFeature.PreferHostingUrls = true;
server.Listener.Options.UrlPrefixes.Add(serverAddress);
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(serverAddress, serverAddressesFeature.Addresses.Single());
}
@@ -84,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
serverAddressesFeature.Addresses.Add(serverAddress);
server.Listener.Options.UrlPrefixes.Add(overrideAddress);
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(overrideAddress, serverAddressesFeature.Addresses.Single());
}
@@ -100,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
var serverAddressesFeature = server.Features.Get();
serverAddressesFeature.Addresses.Add(serverAddress);
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
}
}
@@ -109,7 +110,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{
using (var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory()))
{
- server.Start(new DummyApplication());
+ server.StartAsync(new DummyApplication(), CancellationToken.None).Wait();
Assert.Equal(Constants.DefaultServerAddress, server.Features.Get().Addresses.Single());
}
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
index 1e79dff31b..91e4459b78 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs
@@ -7,6 +7,7 @@ using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
@@ -312,7 +313,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
server.Listener.Options.UrlPrefixes.Add(UrlPrefix.Create(rootUri.Scheme, rootUri.Host, rootUri.Port, path));
}
- server.Start(new DummyApplication(app));
+ server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
return server;
}
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
index 10a356b487..029c259b61 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
@@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Task responseTask;
ManualResetEvent received = new ManualResetEvent(false);
string address;
- using (Utilities.CreateHttpServer(out address, httpContext =>
+ using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{
received.Set();
httpContext.Response.ContentLength = 11;
@@ -82,11 +82,34 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{
responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(10000));
+ await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
}
string response = await responseTask;
Assert.Equal("Hello World", response);
}
+ [ConditionalFact]
+ public async Task Server_DisposeWithoutStopDuringRequest_Aborts()
+ {
+ Task responseTask;
+ var received = new ManualResetEvent(false);
+ var stopped = new ManualResetEvent(false);
+ string address;
+ using (var server = Utilities.CreateHttpServer(out address, httpContext =>
+ {
+ received.Set();
+ Assert.True(stopped.WaitOne(TimeSpan.FromSeconds(10)));
+ httpContext.Response.ContentLength = 11;
+ return httpContext.Response.WriteAsync("Hello World");
+ }))
+ {
+ responseTask = SendRequestAsync(address);
+ Assert.True(received.WaitOne(TimeSpan.FromSeconds(10)));
+ }
+ stopped.Set();
+ await Assert.ThrowsAsync(async () => await responseTask);
+ }
+
[ConditionalFact]
public async Task Server_ShutdownDuringLongRunningRequest_TimesOut()
{
@@ -95,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
bool? shutdown = null;
var waitForShutdown = new ManualResetEvent(false);
string address;
- using (Utilities.CreateHttpServer(out address, httpContext =>
+ using (var server = Utilities.CreateHttpServer(out address, httpContext =>
{
received.Set();
shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15));
@@ -105,8 +128,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{
responseTask = SendRequestAsync(address);
Assert.True(received.WaitOne(TimeSpan.FromSeconds(10)));
+ Assert.False(shutdown.HasValue);
+ await server.StopAsync(new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
}
- Assert.False(shutdown.HasValue);
waitForShutdown.Set();
await Assert.ThrowsAsync(async () => await responseTask);
}
@@ -271,7 +295,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
using (server)
{
- server.Start(new DummyApplication());
+ await server.StartAsync(new DummyApplication(), CancellationToken.None);
string response = await SendRequestAsync(address);
Assert.Equal(string.Empty, response);
}
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs
index 3682e1de5e..5744e35d04 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/Utilities.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Threading;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http;
@@ -55,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
server.Listener.Options.Authentication.AllowAnonymous = allowAnonymous;
try
{
- server.Start(new DummyApplication(app));
+ server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
return server;
}
catch (HttpSysException)
@@ -76,7 +77,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
{
var server = new MessagePump(Options.Create(new HttpSysOptions()), new LoggerFactory());
server.Features.Get().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString());
- server.Start(new DummyApplication(app));
+ server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
return server;
}
}