Signalr: Console application using async/await stops receiving after sending

Created on 22 Mar 2017  ·  4Comments  ·  Source: SignalR/SignalR

I was working on a spike using a pair of console applications to send and receive messages, and hit a bit of odd behavior. In the subscriber application, once it had invoked a method on the Hub using an await, it stopped receiving new messages. Initially this meant it never received messages because it called a Subscribe method right away, but digging into it I found that it would receive quite happily _until_ it called a method.

When the method is invoked with a .Wait() instead of await everything is fine.

I'm not sure if this is to do with the way threads are handled in console applications (as opposed to WPF applications which have a SynchronizationContext), or is down to a problem in the C# SignalR client.

Expected behavior

Would expect to be able to await hubProxy.Invoke("Foo"); and continue to receive messages.

Actual behavior

Using await hubProxy.Invoke("Foo"); breaks the connection somehow.

Steps to reproduce

```c#
class Program
{
static void Main()
{
Run().Wait();
}

static async Task Run()
{
Console.WriteLine("[Subscriber] press Enter to enter...");
Console.ReadLine();

var hubConnection = new HubConnection("http://localhost:39103/");
var hubProxy = hubConnection.CreateHubProxy("MyHub");
hubProxy.On<string>("OnMessage", msg =>
{
  Console.WriteLine($"Received: {msg}");
});

await hubConnection.Start();

// Receiving messages quite happily at this point

Console.WriteLine("And press Enter again to break the application...");
Console.ReadLine();

await hubProxy.Invoke("Foo", "Bar");

// NO MESSAGES FOR YOU!

Console.WriteLine("And press Enter to Exit, because computers...");
Console.ReadLine();

}
}
```

Bug

Most helpful comment

Fixed in e55b89a45618d222e2c37a3b14969923c998899b

All 4 comments

I should point out, the reason I'm concerned about this even though it's just a spike is that the actual service I'm working on will be consumed from ASP.NET Web API services as well as WPF desktop applications.

It's a very implicit deadlock. If you turn on tracing you will see that the messages are still being received by the client only your callback is not being invoked because the previous one has not finished yet:

And press Enter to Exit, because computers...
16:44:27.6966075 - b8022975-3d42-4935-952d-7c43a392d049 - WS: OnMessage({"C":"d-59F20992-B,18|S,0|T,1","M":[{"H":"ChatHub","M":"broadcastMessage","A":["adfasf","sadf"]}]})
16:44:28.6936798 - b8022975-3d42-4935-952d-7c43a392d049 - WS: OnMessage({})
16:44:31.4080330 - b8022975-3d42-4935-952d-7c43a392d049 - WS: OnMessage({"C":"d-59F20992-B,19|S,0|T,1","M":[{"H":"ChatHub","M":"broadcastMessage","A":["adfasf","adfsa"]}]})
16:44:36.2056851 - b8022975-3d42-4935-952d-7c43a392d049 - OnError(Microsoft.AspNet.SignalR.Client.Infrastructure.SlowCallbackException: Possible deadlock detected. A callback registered with "HubProxy.On" or "Connection.Received" has been executing for at least 10 seconds.)
16:44:38.6935113 - b8022975-3d42-4935-952d-7c43a392d049 - WS: OnMessage({})

On your side you could fix this by changing Console.ReadLine(); to await Console.In.ReadLineAsync() but I believe that the root cause here is that by default user code runs on the same thread as the task completed with TaskCompletionSource.SetResult(). The client should dispatch setting result to a different thread or use the TaskCreationOption.RunContinuationsAsynchronously when creating the TCS.

This thread is my async await experience in a nutshell.

Fixed in e55b89a45618d222e2c37a3b14969923c998899b

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cceraja picture cceraja  ·  6Comments

thedutchess picture thedutchess  ·  4Comments

Vaccano picture Vaccano  ·  5Comments

raRaRa picture raRaRa  ·  7Comments

SkyWaterXXS picture SkyWaterXXS  ·  4Comments