Get off the event loop before dispatch (#1952)
This commit is contained in:
parent
12b69a0fdb
commit
cb5bba36fc
|
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Http.Connections.Internal
|
namespace Microsoft.AspNetCore.Internal
|
||||||
{
|
{
|
||||||
public static class AwaitableThreadPool
|
public static class AwaitableThreadPool
|
||||||
{
|
{
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Common\AwaitableThreadPool.cs" Link="AwaitableThreadPool.cs" />
|
||||||
<Compile Include="..\Common\MemoryBufferWriter.cs" Link="MemoryBufferWriter.cs" />
|
<Compile Include="..\Common\MemoryBufferWriter.cs" Link="MemoryBufferWriter.cs" />
|
||||||
<Compile Include="..\Common\PipeWriterStream.cs" Link="PipeWriterStream.cs" />
|
<Compile Include="..\Common\PipeWriterStream.cs" Link="PipeWriterStream.cs" />
|
||||||
<Compile Include="..\Common\WebSocketExtensions.cs" Link="WebSocketExtensions.cs" />
|
<Compile Include="..\Common\WebSocketExtensions.cs" Link="WebSocketExtensions.cs" />
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Connections.Features;
|
using Microsoft.AspNetCore.Connections.Features;
|
||||||
|
using Microsoft.AspNetCore.Internal;
|
||||||
using Microsoft.AspNetCore.SignalR.Internal;
|
using Microsoft.AspNetCore.SignalR.Internal;
|
||||||
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
using Microsoft.AspNetCore.SignalR.Internal.Protocol;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
@ -433,6 +434,9 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
||||||
|
|
||||||
private async Task DispatchInvocationAsync(InvocationMessage invocation)
|
private async Task DispatchInvocationAsync(InvocationMessage invocation)
|
||||||
{
|
{
|
||||||
|
// Make sure we get off the main event loop before we dispatch into user code
|
||||||
|
await AwaitableThreadPool.Yield();
|
||||||
|
|
||||||
// Find the handler
|
// Find the handler
|
||||||
if (!_handlers.TryGetValue(invocation.Target, out var handlers))
|
if (!_handlers.TryGetValue(invocation.Target, out var handlers))
|
||||||
{
|
{
|
||||||
|
|
@ -678,29 +682,30 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
||||||
Log.ShutdownConnection(_logger);
|
Log.ShutdownConnection(_logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire-and-forget the closed event
|
|
||||||
RunClosedEvent(connectionState.CloseException);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RunClosedEvent(Exception closeException)
|
|
||||||
{
|
|
||||||
var closed = Closed;
|
var closed = Closed;
|
||||||
|
|
||||||
// There is no need to start a new task if there is no Closed event registered
|
// There is no need to start a new task if there is no Closed event registered
|
||||||
if (closed != null)
|
if (closed != null)
|
||||||
{
|
{
|
||||||
_ = Task.Run(() =>
|
|
||||||
{
|
// Fire-and-forget the closed event
|
||||||
try
|
_ = RunClosedEvent(closed, connectionState.CloseException);
|
||||||
{
|
}
|
||||||
Log.InvokingClosedEventHandler(_logger);
|
}
|
||||||
closed.Invoke(closeException);
|
|
||||||
}
|
private async Task RunClosedEvent(Action<Exception> closed, Exception closeException)
|
||||||
catch (Exception ex)
|
{
|
||||||
{
|
// Dispatch to the thread pool before we invoke the user callback
|
||||||
Log.ErrorDuringClosedEvent(_logger, ex);
|
await AwaitableThreadPool.Yield();
|
||||||
}
|
|
||||||
});
|
try
|
||||||
|
{
|
||||||
|
Log.InvokingClosedEventHandler(_logger);
|
||||||
|
closed.Invoke(closeException);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.ErrorDuringClosedEvent(_logger, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,7 +930,7 @@ namespace Microsoft.AspNetCore.SignalR.Client
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_stopTcs = new TaskCompletionSource<object>();
|
_stopTcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
return StopAsyncCore(timeout);
|
return StopAsyncCore(timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="..\Common\AwaitableThreadPool.cs" Link="AwaitableThreadPool.cs" />
|
||||||
<Compile Include="..\Common\ForceAsyncAwaiter.cs" Link="ForceAsyncAwaiter.cs" />
|
<Compile Include="..\Common\ForceAsyncAwaiter.cs" Link="ForceAsyncAwaiter.cs" />
|
||||||
<Compile Include="..\Common\PipeWriterStream.cs" Link="PipeWriterStream.cs" />
|
<Compile Include="..\Common\PipeWriterStream.cs" Link="PipeWriterStream.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -485,9 +485,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||||
|
|
||||||
await connection.ReceiveTextAsync(":[\"hello\"]}\u001e");
|
await connection.ReceiveTextAsync(":[\"hello\"]}\u001e");
|
||||||
|
|
||||||
Assert.True(tcs.Task.IsCompleted);
|
var response = await tcs.Task.OrTimeout();
|
||||||
|
|
||||||
var response = await tcs.Task;
|
|
||||||
|
|
||||||
Assert.Equal("hello", response);
|
Assert.Equal("hello", response);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue