@@ -2976,6 +2976,8 @@ public async Task HubMethodInvokeCountsTowardsClientTimeoutIfParallelNotMaxed()
29762976
29772977 // Connection is closed
29782978 await connectionHandlerTask . OrTimeout ( ) ;
2979+
2980+ tcsService . EndMethod . SetResult ( null ) ;
29792981 }
29802982 }
29812983 }
@@ -3223,8 +3225,8 @@ public async Task PendingInvocationUnblockedWhenBlockingMethodCompletesWithParal
32233225 await tcsService . StartedMethod . Task . OrTimeout ( ) ;
32243226 // Grab the tcs before resetting to use in the second long running method
32253227 var endTcs = tcsService . EndMethod ;
3226-
32273228 tcsService . Reset ( ) ;
3229+
32283230 // Long running hub invocation to test that other invocations will not run until it is completed
32293231 await client . SendInvocationAsync ( nameof ( LongRunningHub . LongRunningMethod ) , nonBlocking : false ) . OrTimeout ( ) ;
32303232 // Wait for the long running method to start
@@ -3325,6 +3327,63 @@ public async Task StreamInvocationsBlockOtherInvocationsUntilTheyStartStreaming(
33253327 }
33263328 }
33273329
3330+ [ Fact ]
3331+ public async Task StreamInvocationsDoNotBlockOtherInvocationsWithParallelInvokes ( )
3332+ {
3333+ using ( StartVerifiableLog ( ) )
3334+ {
3335+ var tcsService = new TcsService ( ) ;
3336+ var serviceProvider = HubConnectionHandlerTestUtils . CreateServiceProvider ( builder =>
3337+ {
3338+ builder . AddSingleton ( tcsService ) ;
3339+ builder . AddSingleton ( typeof ( IHubActivator < > ) , typeof ( CustomHubActivator < > ) ) ;
3340+
3341+ builder . AddSignalR ( options =>
3342+ {
3343+ options . MaxParallelInvocationsPerClient = 2 ;
3344+ } ) ;
3345+ } , LoggerFactory ) ;
3346+ var connectionHandler = serviceProvider . GetService < HubConnectionHandler < LongRunningHub > > ( ) ;
3347+
3348+ // Because we use PipeScheduler.Inline the hub invocations will run inline until they wait, which happens inside the LongRunningMethod call
3349+ using ( var client = new TestClient ( ) )
3350+ {
3351+ var connectionHandlerTask = await client . ConnectAsync ( connectionHandler ) . OrTimeout ( ) ;
3352+
3353+ // Long running hub invocation to test that other invocations will not run until it is completed
3354+ var streamInvocationId = await client . SendStreamInvocationAsync ( nameof ( LongRunningHub . LongRunningStream ) , null ) . OrTimeout ( ) ;
3355+ // Wait for the long running method to start
3356+ await tcsService . StartedMethod . Task . OrTimeout ( ) ;
3357+
3358+ // Invoke another hub method which will wait for the first method to finish
3359+ await client . SendInvocationAsync ( nameof ( LongRunningHub . SimpleMethod ) , nonBlocking : false ) . OrTimeout ( ) ;
3360+
3361+ // simple hub method result
3362+ var result = await client . ReadAsync ( ) . OrTimeout ( ) ;
3363+ var simpleCompletion = Assert . IsType < CompletionMessage > ( result ) ;
3364+ Assert . Equal ( 21L , simpleCompletion . Result ) ;
3365+
3366+ // Release the long running hub method
3367+ tcsService . EndMethod . TrySetResult ( null ) ;
3368+
3369+ var hubActivator = serviceProvider . GetService < IHubActivator < LongRunningHub > > ( ) as CustomHubActivator < LongRunningHub > ;
3370+
3371+ await client . SendHubMessageAsync ( new CancelInvocationMessage ( streamInvocationId ) ) . OrTimeout ( ) ;
3372+
3373+ // Completion message for canceled Stream
3374+ await client . ReadAsync ( ) . OrTimeout ( ) ;
3375+
3376+ // Shut down
3377+ client . Dispose ( ) ;
3378+
3379+ await connectionHandlerTask . OrTimeout ( ) ;
3380+
3381+ // OnConnectedAsync, SimpleMethod, LongRunningStream, OnDisconnectedAsync
3382+ Assert . Equal ( 4 , hubActivator . ReleaseCount ) ;
3383+ }
3384+ }
3385+ }
3386+
33283387 [ Fact ]
33293388 public async Task ServerSendsCloseWithErrorWhenConnectionClosedWithPartialMessage ( )
33303389 {
0 commit comments