Honor InherentKeepAliveFeature for server timeout (#2727)
This commit is contained in:
parent
f0c4170e42
commit
e78e3db6f4
|
|
@ -12,6 +12,7 @@ using System.Threading;
|
|||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Client.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
|
|
@ -47,6 +48,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
private long _nextActivationServerTimeout;
|
||||
private long _nextActivationSendPing;
|
||||
private bool _disposed;
|
||||
private bool _hasInherentKeepAlive;
|
||||
|
||||
private readonly ConnectionLogScope _logScope;
|
||||
|
||||
|
|
@ -302,6 +304,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
// Start the connection
|
||||
var connection = await _connectionFactory.ConnectAsync(_protocol.TransferFormat);
|
||||
var startingConnectionState = new ConnectionState(connection, this);
|
||||
_hasInherentKeepAlive = connection.Features.Get<IConnectionInherentKeepAliveFeature>()?.HasInherentKeepAlive ?? false;
|
||||
|
||||
// From here on, if an error occurs we need to shut down the connection because
|
||||
// we still own it.
|
||||
|
|
@ -898,19 +901,25 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
// await returns True until `timer.Stop()` is called in the `finally` block of `ReceiveLoop`
|
||||
while (await timer)
|
||||
{
|
||||
if (DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationServerTimeout))
|
||||
{
|
||||
OnServerTimeout();
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationSendPing))
|
||||
{
|
||||
await PingServer();
|
||||
}
|
||||
await RunTimerActions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Internal for testing
|
||||
internal async Task RunTimerActions()
|
||||
{
|
||||
if (!_hasInherentKeepAlive && DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationServerTimeout))
|
||||
{
|
||||
OnServerTimeout();
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationSendPing))
|
||||
{
|
||||
await PingServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnServerTimeout()
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Buffers;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
|
@ -119,6 +120,33 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
Assert.Equal($"Server timeout ({hubConnection.ServerTimeout.TotalMilliseconds:0.00}ms) elapsed without receiving a message from the server.", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ServerTimeoutIsDisabledWhenUsingTransportWithInherentKeepAlive()
|
||||
{
|
||||
using (StartVerifiableLog(out var loggerFactory))
|
||||
{
|
||||
var testConnection = new TestConnection();
|
||||
testConnection.Features.Set<IConnectionInherentKeepAliveFeature>(new TestKeepAliveFeature() { HasInherentKeepAlive = true });
|
||||
var hubConnection = CreateHubConnection(testConnection, loggerFactory: loggerFactory);
|
||||
hubConnection.ServerTimeout = TimeSpan.FromMilliseconds(1);
|
||||
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
|
||||
var closeTcs = new TaskCompletionSource<Exception>();
|
||||
hubConnection.Closed += ex =>
|
||||
{
|
||||
closeTcs.TrySetResult(ex);
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
await hubConnection.RunTimerActions().OrTimeout();
|
||||
|
||||
Assert.False(closeTcs.Task.IsCompleted);
|
||||
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PendingInvocationsAreTerminatedIfServerTimeoutIntervalElapsesWithNoMessages()
|
||||
{
|
||||
|
|
@ -145,6 +173,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
}
|
||||
}
|
||||
|
||||
private struct TestKeepAliveFeature : IConnectionInherentKeepAliveFeature
|
||||
{
|
||||
public bool HasInherentKeepAlive { get; set; }
|
||||
}
|
||||
|
||||
// Moq really doesn't handle out parameters well, so to make these tests work I added a manual mock -anurse
|
||||
private class MockHubProtocol : IHubProtocol
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue