Wait for requests to drain during shutdown.
This commit is contained in:
parent
60812e51f1
commit
9191bddf00
|
|
@ -39,6 +39,10 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
private int _acceptorCounts;
|
private int _acceptorCounts;
|
||||||
private Action<object> _processRequest;
|
private Action<object> _processRequest;
|
||||||
|
|
||||||
|
private bool _stopping;
|
||||||
|
private int _outstandingRequests;
|
||||||
|
private ManualResetEvent _shutdownSignal;
|
||||||
|
|
||||||
// TODO: private IDictionary<string, object> _capabilities;
|
// TODO: private IDictionary<string, object> _capabilities;
|
||||||
|
|
||||||
internal MessagePump(Microsoft.Net.Server.WebListener listener, ILoggerFactory loggerFactory)
|
internal MessagePump(Microsoft.Net.Server.WebListener listener, ILoggerFactory loggerFactory)
|
||||||
|
|
@ -49,6 +53,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
|
|
||||||
_processRequest = new Action<object>(ProcessRequestAsync);
|
_processRequest = new Action<object>(ProcessRequestAsync);
|
||||||
_maxAccepts = DefaultMaxAccepts;
|
_maxAccepts = DefaultMaxAccepts;
|
||||||
|
_shutdownSignal = new ManualResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Microsoft.Net.Server.WebListener Listener
|
internal Microsoft.Net.Server.WebListener Listener
|
||||||
|
|
@ -108,7 +113,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
private async void ProcessRequestsWorker()
|
private async void ProcessRequestsWorker()
|
||||||
{
|
{
|
||||||
int workerIndex = Interlocked.Increment(ref _acceptorCounts);
|
int workerIndex = Interlocked.Increment(ref _acceptorCounts);
|
||||||
while (_listener.IsListening && workerIndex <= MaxAccepts)
|
while (!_stopping && workerIndex <= MaxAccepts)
|
||||||
{
|
{
|
||||||
// Receive a request
|
// Receive a request
|
||||||
RequestContext requestContext;
|
RequestContext requestContext;
|
||||||
|
|
@ -124,7 +129,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew(_processRequest, requestContext);
|
Task ignored = Task.Factory.StartNew(_processRequest, requestContext);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -141,11 +146,18 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
var requestContext = requestContextObj as RequestContext;
|
var requestContext = requestContextObj as RequestContext;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (_stopping)
|
||||||
|
{
|
||||||
|
SetFatalResponse(requestContext, 503);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Interlocked.Increment(ref _outstandingRequests);
|
||||||
FeatureContext featureContext = new FeatureContext(requestContext);
|
FeatureContext featureContext = new FeatureContext(requestContext);
|
||||||
await _appFunc(featureContext.Features).SupressContext();
|
await _appFunc(featureContext.Features).SupressContext();
|
||||||
// TODO: WebSocket/Opaque upgrade - await requestContext.ProcessResponseAsync().SupressContext();
|
// TODO: WebSocket/Opaque upgrade - await requestContext.ProcessResponseAsync().SupressContext();
|
||||||
|
requestContext.Dispose();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -157,10 +169,16 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We haven't sent a response yet, try to send a 500 Internal Server Error
|
// We haven't sent a response yet, try to send a 500 Internal Server Error
|
||||||
SetFatalResponse(requestContext);
|
SetFatalResponse(requestContext, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (Interlocked.Decrement(ref _outstandingRequests) == 0 && _stopping)
|
||||||
|
{
|
||||||
|
_shutdownSignal.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requestContext.Dispose();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -169,16 +187,24 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetFatalResponse(RequestContext context)
|
private static void SetFatalResponse(RequestContext context, int status)
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = status;
|
||||||
context.Response.ReasonPhrase = string.Empty;
|
context.Response.ReasonPhrase = string.Empty;
|
||||||
context.Response.Headers.Clear();
|
context.Response.Headers.Clear();
|
||||||
context.Response.ContentLength = 0;
|
context.Response.ContentLength = 0;
|
||||||
|
context.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_stopping = true;
|
||||||
|
// Wait for active requests to drain
|
||||||
|
if (_outstandingRequests > 0)
|
||||||
|
{
|
||||||
|
_shutdownSignal.WaitOne();
|
||||||
|
}
|
||||||
|
// All requests are finished
|
||||||
_listener.Dispose();
|
_listener.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,26 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Server_ShutdownDurringRequest_Success()
|
||||||
|
{
|
||||||
|
Task<string> responseTask;
|
||||||
|
ManualResetEvent received = new ManualResetEvent(false);
|
||||||
|
using (Utilities.CreateHttpServer(env =>
|
||||||
|
{
|
||||||
|
received.Set();
|
||||||
|
var httpContext = new DefaultHttpContext((IFeatureCollection)env);
|
||||||
|
httpContext.Response.ContentLength = 11;
|
||||||
|
return httpContext.Response.WriteAsync("Hello World");
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
responseTask = SendRequestAsync(Address);
|
||||||
|
Assert.True(received.WaitOne(10000));
|
||||||
|
}
|
||||||
|
string response = await responseTask;
|
||||||
|
Assert.Equal("Hello World", response);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Server_AppException_ClientReset()
|
public void Server_AppException_ClientReset()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue