Make server timeout configurable (#7340)
This commit is contained in:
parent
8ae4c4dbd6
commit
af43b80b1a
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections
|
||||
{
|
||||
public class ConnectionOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the interval used by the server to timeout idle connections.
|
||||
/// </summary>
|
||||
public TimeSpan? DisconnectTimeout { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections
|
||||
{
|
||||
public class ConnectionOptionsSetup : IConfigureOptions<ConnectionOptions>
|
||||
{
|
||||
public static TimeSpan DefaultDisconectTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
public void Configure(ConnectionOptions options)
|
||||
{
|
||||
if (options.DisconnectTimeout == null)
|
||||
{
|
||||
options.DisconnectTimeout = DefaultDisconectTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http.Connections;
|
||||
using Microsoft.AspNetCore.Http.Connections.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
|
|
@ -20,9 +23,22 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
services.AddRouting();
|
||||
services.AddAuthorizationPolicyEvaluator();
|
||||
services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<ConnectionOptions>, ConnectionOptionsSetup>());
|
||||
services.TryAddSingleton<HttpConnectionDispatcher>();
|
||||
services.TryAddSingleton<HttpConnectionManager>();
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds required services for ASP.NET Core Connection Handlers to the specified <see cref="IServiceCollection" />.
|
||||
/// </summary>
|
||||
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||
/// <param name="options">A callback to configure <see cref="ConnectionOptions" /></param>
|
||||
/// <returns>The same instance of the <see cref="IServiceCollection"/> for chaining.</returns>
|
||||
public static IServiceCollection AddConnections(this IServiceCollection services, Action<ConnectionOptions> options)
|
||||
{
|
||||
return services.Configure(options)
|
||||
.AddConnections();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers.Text;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
|
@ -15,6 +14,7 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.Extensions.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Internal
|
||||
{
|
||||
|
|
@ -30,13 +30,19 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
|
|||
private readonly TimerAwaitable _nextHeartbeat;
|
||||
private readonly ILogger<HttpConnectionManager> _logger;
|
||||
private readonly ILogger<HttpConnectionContext> _connectionLogger;
|
||||
private readonly TimeSpan _disconnectTimeout;
|
||||
|
||||
public HttpConnectionManager(ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
|
||||
: this(loggerFactory, appLifetime, Options.Create(new ConnectionOptions() { DisconnectTimeout = ConnectionOptionsSetup.DefaultDisconectTimeout }))
|
||||
{
|
||||
}
|
||||
|
||||
public HttpConnectionManager(ILoggerFactory loggerFactory, IApplicationLifetime appLifetime, IOptions<ConnectionOptions> connectionOptions)
|
||||
{
|
||||
_logger = loggerFactory.CreateLogger<HttpConnectionManager>();
|
||||
_connectionLogger = loggerFactory.CreateLogger<HttpConnectionContext>();
|
||||
_nextHeartbeat = new TimerAwaitable(_heartbeatTickRate, _heartbeatTickRate);
|
||||
|
||||
_disconnectTimeout = connectionOptions.Value.DisconnectTimeout ?? ConnectionOptionsSetup.DefaultDisconectTimeout;
|
||||
// Register these last as the callbacks could run immediately
|
||||
appLifetime.ApplicationStarted.Register(() => Start());
|
||||
appLifetime.ApplicationStopping.Register(() => CloseConnections());
|
||||
|
|
@ -155,7 +161,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal
|
|||
|
||||
// Once the decision has been made to dispose we don't check the status again
|
||||
// But don't clean up connections while the debugger is attached.
|
||||
if (!Debugger.IsAttached && status == HttpConnectionStatus.Inactive && (DateTimeOffset.UtcNow - lastSeenUtc).TotalSeconds > 5)
|
||||
if (!Debugger.IsAttached && status == HttpConnectionStatus.Inactive && (DateTimeOffset.UtcNow - lastSeenUtc).TotalSeconds > _disconnectTimeout.TotalSeconds)
|
||||
{
|
||||
Log.ConnectionTimedOut(_logger, connection.ConnectionId);
|
||||
HttpConnectionsEventSource.Log.ConnectionTimedOut(connection.ConnectionId);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ using Microsoft.AspNetCore.SignalR.Tests;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Testing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -395,7 +396,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
|||
{
|
||||
using (StartVerifiableLog())
|
||||
{
|
||||
var manager = CreateConnectionManager(LoggerFactory);
|
||||
var manager = CreateConnectionManager(LoggerFactory, TimeSpan.FromSeconds(5));
|
||||
var dispatcher = new HttpConnectionDispatcher(manager, LoggerFactory);
|
||||
var connection = manager.CreateConnection();
|
||||
connection.TransportType = HttpTransportType.LongPolling;
|
||||
|
|
@ -2178,6 +2179,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
|||
return new HttpConnectionManager(loggerFactory ?? new LoggerFactory(), new EmptyApplicationLifetime());
|
||||
}
|
||||
|
||||
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory, TimeSpan disconnectTimeout)
|
||||
{
|
||||
var connectionOptions = new ConnectionOptions();
|
||||
connectionOptions.DisconnectTimeout = disconnectTimeout;
|
||||
return new HttpConnectionManager(loggerFactory ?? new LoggerFactory(), new EmptyApplicationLifetime(), Options.Create(connectionOptions));
|
||||
}
|
||||
|
||||
private string GetContentAsString(Stream body)
|
||||
{
|
||||
Assert.True(body.CanSeek, "Can't get content of a non-seekable stream");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Http.Connections.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||
|
|
|
|||
Loading…
Reference in New Issue