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