This commit is contained in:
Chris R 2017-03-28 15:16:31 -07:00
Родитель bc003985c6
Коммит 4e8872b94d
6 изменённых файлов: 62 добавлений и 32 удалений

Просмотреть файл

@ -79,12 +79,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
}
}
/// <summary>
/// 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.
/// </summary>
public TimeSpan ShutdownTimeout { get; set; } = TimeSpan.FromSeconds(5);
internal void SetRequestQueueLimit(RequestQueue requestQueue)
{
_requestQueue = requestQueue;

Просмотреть файл

@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
private bool _stopping;
private int _outstandingRequests;
private ManualResetEvent _shutdownSignal;
private TaskCompletionSource<object> _shutdownSignal;
private readonly ServerAddressesFeature _serverAddresses;
@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
_processRequest = new Action<object>(ProcessRequestAsync);
_maxAccepts = _options.MaxAccepts;
EnableResponseCaching = _options.EnableResponseCaching;
_shutdownSignal = new ManualResetEvent(false);
_shutdownSignal = new TaskCompletionSource<object>();
}
internal HttpSysListener Listener { get; }
@ -60,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public IFeatureCollection Features { get; }
public void Start<TContext>(IHttpApplication<TContext> application)
public Task StartAsync<TContext>(IHttpApplication<TContext> 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<object>();
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();
}

Просмотреть файл

@ -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<IServerAddressesFeature>();
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<IServerAddressesFeature>().Addresses.Single());
}

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -73,7 +73,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
Task<string> 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<string> 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<HttpRequestException>(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<HttpRequestException>(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);
}

Просмотреть файл

@ -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<IServerAddressesFeature>().Addresses.Add(UrlPrefix.Create(scheme, host, port, path).ToString());
server.Start(new DummyApplication(app));
server.StartAsync(new DummyApplication(app), CancellationToken.None).Wait();
return server;
}
}