Skip to main content

How to setup session affinity in Google Cloud Run with an internal load balancer and configure SignalR to use the session affinity cookie.

---
title: Configure SignalR client to use session affinity cookie
subtitle: How to setup session affinity in Google Cloud Run with an internal load balancer and configure SignalR to use the session affinity cookie.
author: Jon LaBelle
date: September 29, 2024
source: https://jonlabelle.com/snippets/view/markdown/configure-signalr-client-to-use-session-affinity-cookie
notoc: false
---

To set up session affinity in Google Cloud Run with an internal load balancer
and configure SignalR to use the session affinity cookie, follow these steps:

### Step 1: Set Up Session Affinity in Google Cloud Load Balancer

1. **Create a Backend Service with Session Affinity:**

   - Go to the Google Cloud Console.
   - Navigate to the **Load balancing** section.
   - Create or edit a backend service.
   - In the backend service settings, enable **Session Affinity** and choose **Client IP** or **Generated Cookie** as the affinity type.

2. **Configure the Backend Service:**

   - Ensure that the backend service is associated with your Cloud Run service.
   - Save the configuration.

### Step 2: Configure SignalR in .NET Core 8 API

1. **Install SignalR NuGet Package:**

   ```bash
   dotnet add package Microsoft.AspNetCore.SignalR
   ```

2. **Configure SignalR in `Startup.cs`:**

   ```csharp
   public void ConfigureServices(IServiceCollection services)
   {
       services.AddSignalR();
       // Other service configurations
   }

   public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
   {
       app.UseRouting();

       app.UseEndpoints(endpoints =>
       {
           endpoints.MapHub<YourHub>("/yourHub");
           // Other endpoint mappings
       });
   }
   ```

3. **Create a SignalR hub:**

   **Override Hub Methods for Error Handling:** Override methods like `OnConnectedAsync`, `OnDisconnectedAsync`, and `OnReconnectedAsync` to handle connection events and errors. Use logging to capture and log errors for further analysis.

   ```csharp
   using Microsoft.AspNetCore.SignalR;
   using Microsoft.Extensions.Logging;
   using System;
   using System.Threading.Tasks;

   public class YourHub : Hub
   {
       private readonly ILogger<YourHub> _logger;

       public YourHub(ILogger<YourHub> logger)
       {
           _logger = logger;
       }

       public override async Task OnConnectedAsync()
       {
           _logger.LogInformation("Client connected: {ConnectionId}", Context.ConnectionId);

           await base.OnConnectedAsync();
       }

       public override async Task OnDisconnectedAsync(Exception exception)
       {
           if (exception != null)
           {
               _logger.LogError(exception, "Client disconnected with error: {ConnectionId}", Context.ConnectionId);
           }
           else
           {
               _logger.LogInformation("Client disconnected: {ConnectionId}", Context.ConnectionId);
           }

           await base.OnDisconnectedAsync(exception);
       }

       public override async Task OnReconnectedAsync()
       {
           _logger.LogInformation("Client reconnected: {ConnectionId}", Context.ConnectionId);

           await base.OnReconnectedAsync();
       }

       // Example method to handle client messages
       public async Task SendMessage(string message)
       {
           _logger.LogInformation("Received message: {Message}", message);

           await Clients.All.SendAsync("ReceiveMessage", message);
       }
   }
   ```

### Step 3: Configure SignalR Client in Vue.js 3

1. **Install SignalR Client Library:**

   ```bash
   npm install @microsoft/signalr
   ```

2. **Configure SignalR Client to Use Session Affinity Cookie:**

   ```javascript
   import * as signalR from '@microsoft/signalr';

   // Create the connection
   const connection = new signalR.HubConnectionBuilder()
     .withUrl('https://your-api-url/yourHub', {
       withCredentials: true // Ensure cookies are sent with requests
     })
     .build();

   // Start the connection
   connection
     .start()
     .then(() => console.log('SignalR connected'))
     .catch((err) => console.error('SignalR connection error: ', err));

   // Handle connection close
   connection.onclose((error) => {
     if (error) {
       console.error('SignalR connection closed with error: ', error);
     } else {
       console.log('SignalR connection closed.');
     }
     // Optionally, attempt to reconnect
     setTimeout(
       () =>
         connection
           .start()
           .catch((err) => console.error('Reconnection failed: ', err)),
       5000
     );
   });

   // Handle reconnecting
   connection.onreconnecting((error) => {
     console.warn('SignalR reconnecting due to error: ', error);
     // Optionally, display a message to the user
   });

   // Handle reconnected
   connection.onreconnected((connectionId) => {
     console.log('SignalR reconnected. Connection ID: ', connectionId);
     // Optionally, notify the user that the connection has been re-established
   });
   ```

### Summary

1. **Google Cloud Load Balancer:**

   - Enable session affinity in the backend service settings.

2. **.NET Core 8 API:**

   - Install and configure SignalR in your API.

3. **Vue.js 3 Client:**

   - Install SignalR client library and configure it to use session affinity cookies.

This setup ensures that SignalR connections are maintained and not dropped due to load balancing.