LongPolling should not ping (#15352)
This commit is contained in:
parent
8566d663c3
commit
dfba024c78
|
|
@ -1626,6 +1626,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
{
|
||||
private readonly HubConnection _hubConnection;
|
||||
private readonly ILogger _logger;
|
||||
private readonly bool _hasInherentKeepAlive;
|
||||
|
||||
private readonly object _lock = new object();
|
||||
private readonly Dictionary<string, InvocationRequest> _pendingCalls = new Dictionary<string, InvocationRequest>(StringComparer.Ordinal);
|
||||
|
|
@ -1637,7 +1638,6 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
|
||||
private long _nextActivationServerTimeout;
|
||||
private long _nextActivationSendPing;
|
||||
private bool _hasInherentKeepAlive;
|
||||
|
||||
public ConnectionContext Connection { get; }
|
||||
public Task ReceiveTask { get; set; }
|
||||
|
|
@ -1764,7 +1764,10 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
// Old clients never ping, and shouldn't be timed out, so ping to tell the server that we should be timed out if we stop.
|
||||
// The TimerLoop is started from the ReceiveLoop with the connection lock still acquired.
|
||||
_hubConnection._state.AssertInConnectionLock();
|
||||
if (!_hasInherentKeepAlive)
|
||||
{
|
||||
await _hubConnection.SendHubMessage(this, PingMessage.Instance);
|
||||
}
|
||||
|
||||
// initialize the timers
|
||||
timer.Start();
|
||||
|
|
@ -1794,7 +1797,12 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
|||
// Internal for testing
|
||||
internal async Task RunTimerActions()
|
||||
{
|
||||
if (!_hasInherentKeepAlive && DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationServerTimeout))
|
||||
if (_hasInherentKeepAlive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow.Ticks > Volatile.Read(ref _nextActivationServerTimeout))
|
||||
{
|
||||
OnServerTimeout();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -648,6 +648,33 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
await connection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClientWithInherentKeepAliveDoesNotPing()
|
||||
{
|
||||
var connection = new TestConnection(hasInherentKeepAlive: true);
|
||||
var hubConnection = CreateHubConnection(connection);
|
||||
|
||||
hubConnection.TickRate = TimeSpan.FromMilliseconds(30);
|
||||
hubConnection.KeepAliveInterval = TimeSpan.FromMilliseconds(80);
|
||||
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
|
||||
Assert.Equal(0, (await connection.ReadAllSentMessagesAsync(ignorePings: false).OrTimeout()).Count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
await connection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using System.Text;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
|
|
@ -18,7 +19,7 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||
{
|
||||
internal class TestConnection : ConnectionContext
|
||||
internal class TestConnection : ConnectionContext, IConnectionInherentKeepAliveFeature
|
||||
{
|
||||
private readonly bool _autoHandshake;
|
||||
private readonly TaskCompletionSource<object> _started = new TaskCompletionSource<object>();
|
||||
|
|
@ -30,6 +31,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
private readonly Func<Task> _onStart;
|
||||
private readonly Func<Task> _onDispose;
|
||||
private readonly bool _hasInherentKeepAlive;
|
||||
|
||||
public override string ConnectionId { get; set; }
|
||||
|
||||
|
|
@ -41,17 +43,22 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
|
||||
public override IDictionary<object, object> Items { get; set; } = new ConnectionItems();
|
||||
|
||||
public TestConnection(Func<Task> onStart = null, Func<Task> onDispose = null, bool autoHandshake = true)
|
||||
bool IConnectionInherentKeepAliveFeature.HasInherentKeepAlive => _hasInherentKeepAlive;
|
||||
|
||||
public TestConnection(Func<Task> onStart = null, Func<Task> onDispose = null, bool autoHandshake = true, bool hasInherentKeepAlive = false)
|
||||
{
|
||||
_autoHandshake = autoHandshake;
|
||||
_onStart = onStart ?? (() => Task.CompletedTask);
|
||||
_onDispose = onDispose ?? (() => Task.CompletedTask);
|
||||
_hasInherentKeepAlive = hasInherentKeepAlive;
|
||||
|
||||
var options = new PipeOptions(readerScheduler: PipeScheduler.Inline, writerScheduler: PipeScheduler.Inline, useSynchronizationContext: false);
|
||||
|
||||
var pair = DuplexPipe.CreateConnectionPair(options, options);
|
||||
Application = pair.Application;
|
||||
Transport = pair.Transport;
|
||||
|
||||
Features.Set<IConnectionInherentKeepAliveFeature>(this);
|
||||
}
|
||||
|
||||
public override ValueTask DisposeAsync() => DisposeCoreAsync();
|
||||
|
|
@ -119,6 +126,10 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
|||
while (true)
|
||||
{
|
||||
var result = await ReadSentTextMessageAsyncInner();
|
||||
if (result == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var receivedMessageType = (int?)JObject.Parse(result)["type"];
|
||||
|
||||
|
|
|
|||
|
|
@ -589,6 +589,10 @@ export class HubConnection {
|
|||
}
|
||||
|
||||
private resetKeepAliveInterval() {
|
||||
if (this.connection.features.inherentKeepAlive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cleanupPingTimer();
|
||||
this.pingServerHandle = setTimeout(async () => {
|
||||
if (this.connectionState === HubConnectionState.Connected) {
|
||||
|
|
|
|||
|
|
@ -127,6 +127,25 @@ describe("HubConnection", () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("does not send pings for connection with inherentKeepAlive", async () => {
|
||||
await VerifyLogger.run(async (logger) => {
|
||||
const connection = new TestConnection(true, true);
|
||||
const hubConnection = createHubConnection(connection, logger);
|
||||
|
||||
hubConnection.keepAliveIntervalInMilliseconds = 5;
|
||||
|
||||
try {
|
||||
await hubConnection.start();
|
||||
await delayUntil(500);
|
||||
|
||||
const numPings = connection.sentData.filter((s) => JSON.parse(s).type === MessageType.Ping).length;
|
||||
expect(numPings).toEqual(0);
|
||||
} finally {
|
||||
await hubConnection.stop();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("stop", () => {
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ export class TestConnection implements IConnection {
|
|||
|
||||
private autoHandshake: boolean | null;
|
||||
|
||||
constructor(autoHandshake: boolean = true) {
|
||||
constructor(autoHandshake: boolean = true, hasInherentKeepAlive: boolean = false) {
|
||||
this.onreceive = null;
|
||||
this.onclose = null;
|
||||
this.sentData = [];
|
||||
this.lastInvocationId = null;
|
||||
this.autoHandshake = autoHandshake;
|
||||
this.baseUrl = "http://example.com";
|
||||
this.features.inherentKeepAlive = hasInherentKeepAlive;
|
||||
}
|
||||
|
||||
public start(): Promise<void> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue