Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring

Near Real-Time Transient Clients

Component: NServiceBus
NuGet Package: NServiceBus (8.x)

For near real-time, occasionally connected clients, messages are only relevant for a short period of time. Clients that received near real-time stock ticker updates are a common example of these types of clients.

One of the basic features of message queuing is the ability for the receiving endpoints to maintain service even when offline. In this scenario, the long lasting, durable nature of message queuing can result in a backlog of messages that are no longer relevant which, if disconnected long enough, can result in queue quotas being exceeded. This can ultimately result in exceptions on the message sender possibly impacting other parts of the system.

A possible answer is to unsubscribe on shutdown. This is a fragile option since the client may not successfully complete the unsubscribe when a crash occurs.

Another solution is to avoid implementing each client as an NServiceBus endpoint, but instead use a push technology, such as SignalR, to update clients only while they are connected.

This sample demonstrates how to use a SignalR server, which also acts as an NServiceBus endpoint, to push subscribed NServiceBus events to any connected SignalR clients.

Project structure

Before running the sample, review the solution structure, the projects, and the classes. The Publisher and ClientHub projects are command-line applications that host an instance of NServiceBus.

The ClientHub project also hosts a SignalR server. The Client project is a command-line application that hosts a SignalR client.

Sharing message types with SignalR

The StockEvents project contains the definition of a message class that is shared with both NServiceBus endpoints, the SignalR hub, and the SignalR client. Open "StockTick" to see the message that will be published by this sample. Note that this event is defined using unobtrusive mode message conventions, allowing the Client project, which only uses SignalR, to reference the message type without requiring a reference to NServiceBus.

var conventions = endpointConfiguration.Conventions();
conventions.DefiningEventsAs(type => type == typeof(StockTick));

Hosting SignalR with NServiceBus

The sample shows how to host a self-hosted SignalR server side-by-side with an NServiceBus endpoint.

Bridging the bus to clients using SignalR

The ClientHub project subscribes to the StockTick event published by Publisher.

StockTickHub defines an async method - PushStockTick - that sends the StockTick message to the connected SignalR clients.

public class StockTicksHub :
    Hub<IEmitStockTicks>
{
}

public interface IEmitStockTicks
{
    Task PushStockTick(StockTick tick);
}

When the StockTick event is handled, it invokes the PushStockTick method on the StockTickHub.

public class StockTickHandler :
    IHandleMessages<StockTick>
{
    static readonly ILog log = LogManager.GetLogger<StockTickHandler>();
    readonly IHubContext<StockTicksHub> hub;

    public StockTickHandler(IHubContext<StockTicksHub> hub)
    {
        this.hub = hub;
    }

    public Task Handle(StockTick message, IMessageHandlerContext context)
    {
        log.Info($"StockTick event received for Symbol {message.Symbol} with timestamp: {message.Timestamp:O}. Press any key to exit.");
        return hub.Clients.All.SendAsync("PushStockTick", message, context.CancellationToken);
    }
}

Web applications

In this sample, the SignalR client is implemented as a .NET console application. The client could also be implemented using the JavaScript SignalR client hosted in a web application.

Scaling out SignalR with NServiceBus

When the number of connected clients exceeds the capability of a single SignalR server, it will be necessary to scale out the SignalR server. Scaling out SignalR is described in the ASP.NET Core SignalR hosting and scaling article by Microsoft.

graph TD NP[NSB Publisher] subgraph Scaled-out Server 1 NS1[NSB Subscriber instance 1] SS1[SignalR Host] end subgraph Scaled-out Server 2 NS2[NSB Subscriber instance 2] SS2[SignalR Host] end subgraph Load Balancer CA(SignalR Client A) CB(SignalR Client B) CC(SignalR Client C) CD(SignalR Client D) end BP{"SignalR Backplane<br/>(Redis/ASB/SQL)"} NP -->|NSB Event|NS1 NS1-->|Forward|SS1 NS2-->|Forward|SS2 SS1-->|Broadcast|BP BP-->SS2 SS1-->|SignalR Message|CA SS1-->|SignalR Message|CB SS2-->|SignalR Message|CC SS2-->|SignalR Message|CD

In this diagram an NServiceBus event is being processed by one of the two subscriber instances. Server 1 is forwarding the NServiceBus event as a SignalR message, which is then broadcast via the configured backplane to Server 2's SignalR server. This allows the connected SignalR clients to receive the message.

Samples

Related Articles