diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
index 2c97b4e..fe0c6d1 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysOptions.cs
@@ -81,6 +81,12 @@ public long RequestQueueLimit
}
}
+ ///
+ /// 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 bd6dbec..2392156 100644
--- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs
+++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs
@@ -221,7 +221,15 @@ public void Dispose()
if (_outstandingRequests > 0)
{
LogHelper.LogInfo(_logger, "Stopping, waiting for " + _outstandingRequests + " request(s) to drain.");
- _shutdownSignal.WaitOne();
+ var drained = _shutdownSignal.WaitOne(Listener.Options.ShutdownTimeout);
+ if (drained)
+ {
+ LogHelper.LogInfo(_logger, "All requests drained successfully.");
+ }
+ else
+ {
+ LogHelper.LogInfo(_logger, "Timed out, terminating " + _outstandingRequests + " request(s).");
+ }
}
// All requests are finished
_listener.Dispose();
diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
index 2794e46..2ae9440 100644
--- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
+++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/ServerTests.cs
@@ -68,7 +68,7 @@ public async Task Server_EchoHelloWorld_Success()
}
[ConditionalFact]
- public async Task Server_ShutdownDurringRequest_Success()
+ public async Task Server_ShutdownDuringRequest_Success()
{
Task responseTask;
ManualResetEvent received = new ManualResetEvent(false);
@@ -87,6 +87,30 @@ public async Task Server_ShutdownDurringRequest_Success()
Assert.Equal("Hello World", response);
}
+ [ConditionalFact]
+ public async Task Server_ShutdownDuringLongRunningRequest_TimesOut()
+ {
+ Task responseTask;
+ var received = new ManualResetEvent(false);
+ bool? shutdown = null;
+ var waitForShutdown = new ManualResetEvent(false);
+ string address;
+ using (Utilities.CreateHttpServer(out address, httpContext =>
+ {
+ received.Set();
+ shutdown = waitForShutdown.WaitOne(TimeSpan.FromSeconds(15));
+ httpContext.Response.ContentLength = 11;
+ return httpContext.Response.WriteAsync("Hello World");
+ }))
+ {
+ responseTask = SendRequestAsync(address);
+ Assert.True(received.WaitOne(TimeSpan.FromSeconds(10)));
+ }
+ Assert.False(shutdown.HasValue);
+ waitForShutdown.Set();
+ await Assert.ThrowsAsync(async () => await responseTask);
+ }
+
[ConditionalFact]
public void Server_AppException_ClientReset()
{