question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

SignalR streaming client can hang indefinitely if it does not receive a Completion on the streaming Channel

See original GitHub issue

I have a pretty generic SignalR server-to-client streaming implementation with a .NET client. The hub exposes a streaming method like so:

public ChannelReader<byte[]> Retrieve(Guid id, CancellationToken cancellationToken)
{
    var channel = Channel.CreateBounded<byte[]>(_limit);
    _ = WriteItemsAsync(channel.Writer, id, cancellationToken);
    return channel.Reader;
}

private async Task WriteItemsAsync(ChannelWriter<byte[]> writer, Guid id, CancellationToken cancellationToken)
{
    Exception localException = null;
    try
    {
        //loop and write to the ChannelWriter until finished
    }
    catch (Exception ex)
    {
        localException = ex;
    }
    finally
    {
        writer.Complete(localException);
    }
}

and the client consumes the stream like this:

var channel = await hubConnection.StreamAsChannelAsync<byte[]>("Retrieve", _guid, cancellationTokenSource.Token);

while (await channel.WaitToReadAsync())
{
    while (channel.TryRead(out var data))
    {
        //handle data
    }
}

The client feeds the stream into a data flow pipeline and the server will call Complete on the Channel when that particular stream is done. The problem is that very seldomly (once every few thousand streaming sessions) the entire pipeline will hang completely, with the effect being that the client thinks it is still processing a stream and won’t request any further streams from the server, causing the whole pipeline to come to a halt.

My server logs will show that the server has called Complete on the ChannelWriter in the hub, but that the client is still blocking at await channel.WaitToReadAsync() as if it has not seen the Complete message. Because it has only happened a handful of times, I don’t have steps to reproduce it yet and I am not 100% positive SignalR is the culprit, but an answer to the following would help me narrow it down.

So my question: when the hub calls Complete on a streaming Channel, is that Complete message guaranteed to make it to the client, or is it possible that the message doesn’t make it in a rare case and the client blocks forever on a stream that is effectively closed? Obviously normal SignalR messages are “fire and forget”, but do the completion messages that SignalR sends under the hood for streams follow the same rules?

My workaround right now is to use the CancelAfter method of a CancellationTokenSource to allow me to timeout the streaming client if it hasn’t received any messages on the open stream within a given time span. I’ll be able to share more data when the next hang occurs.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
davidfowlcommented, Feb 12, 2021

Right it should never hang forever. It’ll either send the complete message or disconnect. Either way, a hang would be a bug in the client

0reactions
koopaking3commented, Feb 12, 2021

Thanks again! I’ll close the issue and reopen later if I’m able to get a dump and there is a related issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - When using Channels with SignalR server-to-client ...
In both cases the channel on the client side will be completed." And: "Right it should never hang forever. It'll either send the...
Read more >
SignalR: when streaming from client to server, if ...
When the channel is completed with an exception on the client, then on the server, the stream.WaitToReadAsync() task is not completed with ...
Read more >
Understanding and Handling Connection Lifetime Events ...
This article provides an overview of the SignalR connection, reconnection, and disconnection events that you can handle, and timeout and ...
Read more >
Use streaming in ASP.NET Core SignalR
Server-to-client streaming hub methods can accept a CancellationToken parameter that's triggered when the client unsubscribes from the stream.
Read more >
Streaming in SignalR - Scientific Programmer
In this type of streaming, we open a stream from the client. The client will then carry on sending messages via the stream...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found