In this lesson, you will learn how to prevent server memory exhaustion when your SignalR clients cannot process incoming high-frequency data streams as fast as your Hub produces them.
The Backpressure Problem
In a real-time system, a mismatch between the rate of data production and the rate of data consumption creates "backpressure." When your Hub continuously pushes data to a slow consumer, SignalR buffers these messages in the server's memory. If the buffer overflows, you risk high latency, excessive memory consumption, or even an OutOfMemoryException. Because SignalR uses persistent connections, the server must manage these queues per client.
Implementing Throttling and Conflation
To mitigate this, you should avoid "fire and forget" streaming. Instead, implement a strategy to throttle or conflate data at the source before it ever hits the SignalR pipeline.
A common approach is using System.Threading.Channels. You can decouple the high-speed data ingestion from the actual delivery to the client.
// Use a Bounded Channel to enforce a limit on pending messages
var channel = Channel.CreateBounded<StockData>(new BoundedChannelOptions(100)
{
FullMode = BoundedChannelFullMode.DropOldest
});
// Producing: Try to write; if full, the oldest data is dropped
channel.Writer.TryWrite(newData);
// Consuming: Stream the data to the client
public async IAsyncEnumerable<StockData> StreamData([EnumeratorCancellation] CancellationToken ct)
{
await foreach (var item in channel.Reader.ReadAllAsync(ct))
{
yield return item;
}
}
Why This Works
By using a BoundedChannel with BoundedChannelFullMode.DropOldest, you enforce a strict limit on how many messages a client can have "in flight." If the client’s network connection slows down or their browser thread is busy, the channel hits its capacity. Instead of crashing your server, the oldest data points are discarded in favor of the most recent information. In most real-time dashboard scenarios, the most recent update is significantly more valuable than stale queued data.
Key Takeaway: Manage backpressure by implementing bounded buffers and data-dropping strategies at the ingestion point to ensure your server memory remains stable despite client-side latency.