diff --git a/NuGet.config b/NuGet.config index 1ea5b4e25974..3fbb60b97541 100644 --- a/NuGet.config +++ b/NuGet.config @@ -6,8 +6,10 @@ + + @@ -30,8 +32,10 @@ + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9fd99628292c..71745ed7054e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -9,325 +9,325 @@ --> - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 1bea6ab613ce7346af69753850e0dd7eb774bc8a + 001e1d31c562c1d246e5a6531b607bf6c851f688 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 https://github.com/dotnet/xdt @@ -367,9 +367,9 @@ bc1c3011064a493b0ca527df6fb7215e2e5cfa96 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 @@ -380,9 +380,9 @@ - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - 19c07820cb72aafc554c3bc8fe3c54010f5123f0 + 4250c8399aa851d2d6a95efbdcc5c4c12311e024 https://github.com/dotnet/winforms diff --git a/eng/Versions.props b/eng/Versions.props index 9acf5b324834..0adfdf1576c5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -67,92 +67,92 @@ --> - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14-servicing.26119.10 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14-servicing.26119.10 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14-servicing.26119.10 - 9.0.14-servicing.26119.10 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15-servicing.26175.22 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15-servicing.26175.22 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15-servicing.26175.22 + 9.0.15-servicing.26175.22 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 - 9.0.14-servicing.26119.10 - 9.0.14 + 9.0.15-servicing.26175.22 + 9.0.15 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 10.6.0-preview.1.26210.2 10.6.0-preview.1.26210.2 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 - 9.0.14 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 + 9.0.15 4.11.0-3.24554.2 4.11.0-3.24554.2 diff --git a/src/SignalR/common/Shared/MessageBuffer.cs b/src/SignalR/common/Shared/MessageBuffer.cs index aa1d6cdded32..b77d6612f7f7 100644 --- a/src/SignalR/common/Shared/MessageBuffer.cs +++ b/src/SignalR/common/Shared/MessageBuffer.cs @@ -33,6 +33,7 @@ internal sealed class MessageBuffer : IDisposable #if NET8_0_OR_GREATER private readonly PeriodicTimer _timer; + private readonly TimeProvider _timeProvider; #else private readonly TimerAwaitable _timer = new(AckRate, AckRate); #endif @@ -68,8 +69,8 @@ public MessageBuffer(ConnectionContext connection, IHubProtocol protocol, long b public MessageBuffer(ConnectionContext connection, IHubProtocol protocol, long bufferLimit, ILogger logger, TimeProvider timeProvider) { #if NET8_0_OR_GREATER - timeProvider ??= TimeProvider.System; - _timer = new(AckRate, timeProvider); + _timeProvider = timeProvider; + _timer = new(AckRate, _timeProvider); #endif _buffer = new LinkedBuffer(); @@ -132,14 +133,17 @@ public ValueTask WriteAsync(HubMessage hubMessage, CancellationToke private async ValueTask WriteAsyncCore(Type hubMessageType, ReadOnlyMemory messageBytes, CancellationToken cancellationToken) { - // If backpressure is being observed a cancelable token is needed to make sure we can break out of waiting when the connection is closed - Debug.Assert(cancellationToken.CanBeCanceled); - // TODO: Add backpressure based on message count if (_bufferedByteCount > _bufferLimit) { +#if NET + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5), _timeProvider); +#else + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); +#endif + using var _ = CancellationTokenUtils.CreateLinkedToken(cts.Token, cancellationToken, out var linkedToken); // primitive backpressure if buffer is full - while (await _waitForAck.Reader.WaitToReadAsync(cancellationToken).ConfigureAwait(false)) + while (await _waitForAck.Reader.WaitToReadAsync(linkedToken).ConfigureAwait(false)) { if (_waitForAck.Reader.TryRead(out var count) && count < _bufferLimit) { diff --git a/src/SignalR/server/Core/src/HubConnectionContext.cs b/src/SignalR/server/Core/src/HubConnectionContext.cs index ffa26c1d0db9..fa47ff052d73 100644 --- a/src/SignalR/server/Core/src/HubConnectionContext.cs +++ b/src/SignalR/server/Core/src/HubConnectionContext.cs @@ -276,19 +276,14 @@ private ValueTask WriteCore(HubMessage message, CancellationToken c static async ValueTask WriteAsync(MessageBuffer messageBuffer, HubConnectionContext hubConnectionContext, HubMessage message, CancellationToken cancellationToken) { - CancellationTokenSource? cts = null; var connectionToken = hubConnectionContext.ConnectionAborted; if (message is CloseMessage) { // If it's a CloseMessage, we might already have triggered the ConnectionAborted token - // We would like to successfully send the CloseMessage for graceful close which means we can't use the ConnectionAborted token, - // but we need to make sure we don't get blocked by backpressure or anything, so we use a short-lived token. - cts = new CancellationTokenSource(TimeSpan.FromSeconds(5), hubConnectionContext._timeProvider); - connectionToken = cts.Token; + // We would like to successfully send the CloseMessage for graceful close which means we can't use the ConnectionAborted token. + connectionToken = CancellationToken.None; } - using var __ = cts; - // MessageBuffer can wait on things other than the PipeWriter (which is canceled by other means) // So we need to make sure the cancellation token passed to it is also canceled when the connection is aborted using var _ = CancellationTokenUtils.CreateLinkedToken(connectionToken, cancellationToken, out var linkedToken); diff --git a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs index 02eadecfacef..37f31cd24817 100644 --- a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs +++ b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/HubConnectionHandlerTests.cs @@ -5272,11 +5272,13 @@ public enum CloseScenario { PingTimeout, Abort, + BackpressureTimeout, } [Theory] [InlineData(CloseScenario.PingTimeout)] [InlineData(CloseScenario.Abort)] + [InlineData(CloseScenario.BackpressureTimeout)] public async Task StatefulReconnectWithMessageBufferBackpressureIsCancelable(CloseScenario scenario) { using (StartVerifiableLog(write => write.EventId.Name == "FailedWritingMessage")) @@ -5307,29 +5309,34 @@ public async Task StatefulReconnectWithMessageBufferBackpressureIsCancelable(Clo await client2.SendHubMessageAsync(new InvocationMessage(nameof(MethodHub.BroadcastMethod), [new string('a', 100)])); + Assert.IsType(await client2.ReadAsync().DefaultTimeout()); + + await client2.SendHubMessageAsync(new InvocationMessage(nameof(MethodHub.BroadcastMethod), [new string('a', 100)])); + switch (scenario) { case CloseScenario.PingTimeout: - { - // We go over the 100 ms timeout interval multiple times - for (var i = 0; i < 3; i++) { - timeProvider.Advance(timeout + TimeSpan.FromMilliseconds(1)); - client1.TickHeartbeat(); + // We go over the 100 ms timeout interval multiple times + for (var i = 0; i < 3; i++) + { + timeProvider.Advance(timeout + TimeSpan.FromMilliseconds(1)); + client1.TickHeartbeat(); + } + break; } - break; - } case CloseScenario.Abort: - { - client1.Connection.Abort(); - break; - } + { + client1.Connection.Abort(); + break; + } + case CloseScenario.BackpressureTimeout: + { + timeProvider.Advance(TimeSpan.FromSeconds(5) + TimeSpan.FromMilliseconds(1)); + break; + } } - Assert.IsType(await client2.ReadAsync().DefaultTimeout()); - - await client2.SendHubMessageAsync(new InvocationMessage(nameof(MethodHub.BroadcastMethod), [new string('a', 100)])); - // This one might not be blocked on client1 if the server sends to client2 first during Broadcast Assert.IsType(await client2.ReadAsync().DefaultTimeout()); diff --git a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs index 37636e771d9a..326ae611d7de 100644 --- a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs +++ b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs @@ -563,7 +563,7 @@ public async Task SendingAckMessageDelayedDuringResend() } [Fact] - public async Task BackpressureWriteMessageCanBeCanceled() + public async Task PipeBackpressureWriteMessageCanBeCanceled() { var cts = new CancellationTokenSource(); var protocol = new JsonHubProtocol(); @@ -581,7 +581,7 @@ public async Task BackpressureWriteMessageCanBeCanceled() cts.Cancel(); - await Assert.ThrowsAnyAsync(async () => await writeTask); + await Assert.ThrowsAnyAsync(async () => await writeTask).DefaultTimeout(); DuplexPipe.UpdateConnectionPair(ref pipes, connection, pipeOptions); var resendTask = messageBuffer.ResendAsync(pipes.Transport.Output); @@ -607,6 +607,94 @@ public async Task BackpressureWriteMessageCanBeCanceled() await resendTask; } + + [Fact] + public async Task BufferedBackpressureWriteMessageDefaultCancellation() + { + var cts = new CancellationTokenSource(); + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipeOptions = new PipeOptions(pauseWriterThreshold: 100, resumeWriterThreshold: 50); + var pipes = DuplexPipe.CreateConnectionPair(new PipeOptions(), pipeOptions); + connection.Transport = pipes.Transport; + var timeProvider = new FakeTimeProvider(); + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 50, NullLogger.Instance, timeProvider); + + await messageBuffer.WriteAsync(new SerializedHubMessage(new InvocationMessage("t", new object[] { new byte[40] })), cts.Token); + + // Write will hit pipe backpressure + var writeTask = messageBuffer.WriteAsync(new SerializedHubMessage(new InvocationMessage("t", new object[] { new byte[40] })), cts.Token); + Assert.False(writeTask.IsCompleted); + + timeProvider.Advance(TimeSpan.FromSeconds(5) + TimeSpan.FromMilliseconds(1)); + + await Assert.ThrowsAnyAsync(async () => await writeTask).DefaultTimeout(); + + DuplexPipe.UpdateConnectionPair(ref pipes, connection, pipeOptions); + var resendTask = messageBuffer.ResendAsync(pipes.Transport.Output); + + var res = await pipes.Application.Input.ReadAsync(); + var buffer = res.Buffer; + Assert.True(protocol.TryParseMessage(ref buffer, new TestBinder(), out var message)); + Assert.IsType(message); + + pipes.Application.Input.AdvanceTo(buffer.Start); + + res = await pipes.Application.Input.ReadAsync(); + buffer = res.Buffer; + Assert.True(protocol.TryParseMessage(ref buffer, new TestBinder(), out message)); + Assert.IsType(message); + + pipes.Application.Input.AdvanceTo(buffer.Start); + + Assert.False(pipes.Application.Input.TryRead(out res)); + + await resendTask; + } + + [Fact] + public async Task BufferedBackpressureWriteMessageCanBeCanceled() + { + var cts = new CancellationTokenSource(); + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipeOptions = new PipeOptions(pauseWriterThreshold: 100, resumeWriterThreshold: 50); + var pipes = DuplexPipe.CreateConnectionPair(new PipeOptions(), pipeOptions); + connection.Transport = pipes.Transport; + var timeProvider = new FakeTimeProvider(); + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 50, NullLogger.Instance, timeProvider); + + await messageBuffer.WriteAsync(new SerializedHubMessage(new InvocationMessage("t", new object[] { new byte[40] })), cts.Token); + + // Write will hit pipe backpressure + var writeTask = messageBuffer.WriteAsync(new SerializedHubMessage(new InvocationMessage("t", new object[] { new byte[40] })), cts.Token); + Assert.False(writeTask.IsCompleted); + + cts.Cancel(); + + await Assert.ThrowsAnyAsync(async () => await writeTask).DefaultTimeout(); + + DuplexPipe.UpdateConnectionPair(ref pipes, connection, pipeOptions); + var resendTask = messageBuffer.ResendAsync(pipes.Transport.Output); + + var res = await pipes.Application.Input.ReadAsync(); + var buffer = res.Buffer; + Assert.True(protocol.TryParseMessage(ref buffer, new TestBinder(), out var message)); + Assert.IsType(message); + + pipes.Application.Input.AdvanceTo(buffer.Start); + + res = await pipes.Application.Input.ReadAsync(); + buffer = res.Buffer; + Assert.True(protocol.TryParseMessage(ref buffer, new TestBinder(), out message)); + Assert.IsType(message); + + pipes.Application.Input.AdvanceTo(buffer.Start); + + Assert.False(pipes.Application.Input.TryRead(out res)); + + await resendTask; + } } internal sealed class TestConnectionContext : ConnectionContext