Practical ASP.NET Core SignalR: Scaling

In this section, I’m going to cover how to deal with scaling SignalR when in a server farm behind a load balancer.

ASP.NET Core SignalR Scaling

Typically to scale we would introduce a load balancer and additional instances of our application.

Introducing multiple instances of our application with SignlaR behind a load balancer is a problem because SignalR keeps track of connected clients in each instance.

This blog post is apart of a course that is a complete step-by-setup guide on how to build real-time web applications using ASP.NET Core SignalR. By the end of this course, you’ll be able to build real-world, scalable, production applications using the tools and techniques provided in this course.

If you haven’t already, check out the prior sections of this course.

  1. Course Overview
  2. ASP.NET Core SignalR Overview
  3. Basics
  4. Server Hubs
  5. HubContext
  6. Authorization

SignalR Scaling

The diagram below illustrates that we have 3 instances of our ASP.NET Core application behind a load balancer. When Client A makes a SignalR connection it is passed off to Instance #1. When Client B connects, it may get passed to Instance #2. Both instances are unaware of the other connected clients and there will be no communication between both.

Meaning, if you call Clients.All.SendAsync() from a Server Hub or HubContext, you will only be sending to the clients connected to that instance.

Redis

You can use Redis as a backplan which keeps information about all connected clients. SignalR uses the pub/sub feature to send messages to other servers. This solves the issue that if you call Clients.All.SendAsync() the message will be sent to all clients from all server.

If you’re using ASP.NET Core 2.2 or later the recommended package to use is: Microsoft.AspNetCore.SignalR.StackExchangeRedis which relies on StackExchangeRedis 2.x.

If you are using ASP.NET Core 2.1, you can use
Microsoft.AspNetCore.SignalR.Redis which relies on StackExchangeRedis 1.x.

Configuring

Depending on which package you are using you must call to add Redis to your AddSignalR() in your startups ConfigureServices()

You can also specify configuration options. In this example, I’m configuring the ClientName of the Redis connection.

To confirm my SignalR Hub is now using Redis, I’ll take a look at the connections in my Redis instance I’m hosting in a Docker container.

Sticky Sessions

There is one caveat when using a Redis backplane. If you are using anything other then WebSockets, meaning you are using Server-Sent Events or Long Polling, you must configure your load balancer to support sticky sessions. Sticky sessions are also known as client affinity and can be enabled in both Azure and AWS.

Get The Course!

You’ve got several options:

  1. Check out my Practical ASP.NET Core SignalR playlist on my CodeOpinion YouTube channel.
  2. Access the full course now by enrolling for free on Teachable.
  3. Follow along with the blog post series here on CodeOpinion.com
    1. Course Overview
    2. ASP.NET Core SignalR Overview
    3. Basics
    4. Server Hubs
    5. HubContext
    6. Authorization
    7. Scaling with Redis
    8. Scaling with Azure SignalR Service

Source Code

All of the source code for this blog post and this course is available the Practical.AspNetCore.SignalR repo on GitHub.

Azure Cosmos DB Caching Tips

I’ve started to use Azure Cosmos DB a bit more over the last couple weeks and I’m really enjoying it.  The first real world scenario that I hit was needing to implement optimistic concurrency. This led me straight into I discovered two caching optimizations you can make for better performance accessing individual documents.

Caching SelfLinks

If you are using the .NET SDK, each document contains a unique SelfLink property.  This is represented by the _self property in the JSON.
They are guaranteed to be unique and most importantly immutable. Because the SelfLink is immutable we can cache it and and then use it to access the associated document. It is more efficient to access the document directly via the SelfLink rather than querying the collection and filtering by Id.

ETags

Each document within Azure Cosmos DB also has has an ETag Property.  This is the _etag in the json document or when you are using the .NET SDK as the ETag on your Document.
The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for web cache validation, which allows a client to make conditional requests.
You may be familiar with ETag’s related caching.  A typical scenario is a user makes an HTTP request to the server for a specific resource.  The server will return the response along with an ETag in the response header.  The client then caches the response along with the associated ETag.
ETag: "686897696a7c876b7e"
If they client then makes another request to the same resource, it will pass a If-Non-Match header with the ETag it received.
If-None-Match: "686897696a7c876b7e"
If the resource has not changed and the ETag represents the current version, then the server will return a 304 Not modified status.  If the resource has been modified, it will return the appropriate 200 status code along with the content new ETag header.

AccessCondition

Azure Cosmos DB uses ETags for handling caching exactly as you would expect for caching.  We can store ETag when we retrieve our document and then subsequently use that ETag when we need to fetch the same document again.  We can do this by creating an AccessCondition and specifying an IfNonMatch as the AccessConditionType when we call ReadDocumentAsync.

Cache Client

Putting it all together can look something like this.  I’m using the MemoryCache to store our fetched documents.  Since these documents contain the SelfLink we can make any other request to that document directly.  Also with the ETag on the document, when we query the document directly, we can specify an If-None-Match for the server to return us a 304 Not Modified.
Since this is just a simple extension method on the DocumentClient, here are a couple of tests that verify that the document is from the cache when the server returns a 304.
 

Demo Source Code

I’ve put together a small .NET Core sample with an XUnit test from above. All the source code for this series is available on GitHub. Are you using Azure Cosmos DB? I’d love to hear your experiences so far along. Let me know on twitter or in the comments.

 

Code Reviews with Visual Studio

Code Reviews with Visual Studio

 

Code reviews are one of the most important development practices to improves quality, reduces bugs, and knowledge sharing.   Here is how to perform Code Reviews with Visual Studio.

In order to use code reviews with Visual Studio, you must be using TFVS (Team Foundation Version Control) within Visual Studio Online or Team Foundation

Request Code Review

Before you commit your changes, in the team explorer go to the My Work section.  Create your code review request by specifying the reviewer (who you want to perform the code review), title, area path, and description.

Code Reviews with Visual Studio

 

Code Reviews with Visual Studio

 

After submitting the code review request, you can suspend your current work while you wait for feedback from the code reviewer.  This allows you to begin work on another product backlog item.

Code Reviews with Visual Studio

 

Perform Code Review

Once a code review request has been sent to you, you can see it from the My Work section.

Code Reviews with Visual Studio

 

Opening the code review will show you the files modified so you can review with the standard diff view.  You can add comments to each file change to let the author know of any suggested changes.

Code Reviews with Visual Studio

 

Resume Work and Review Feedback

Once your code has been reviewed, you can resume your suspended work and view the feedback from the code reviewer.

Code Reviews with Visual Studio

 

Code Reviews with Visual Studio

 

Get Notified!

Once you start using the above workflow, you may want to get notified via email when someone sends you a code review request.  To do so from Visual Studio, in the Team Explorer access the Settings section.

Code Reviews with Visual Studio

 

This will open up Visual Studio online in your browser where you can manage your basic alerts.

Code Reviews with Visual Studio