SignalR + Redis in cluster not working

1.7k Views Asked by At

Background

When running the website with single application instance (container) - SignalR is working perfectly.

When scaling out to more instances (>1), it throws errors and is just not working. I looked for an explanation on the internet and found that I need to configure my Signalr to work in cluster. I choose Redis as my backplane.

I worked through many tutorials on how to do it right and it's just not working for me.

Environment

I working asp.net core v2.1 hosted in Google cloud. The application is deployed as Docker container, using Kestrel + nginx. The docker container runs in a Kubernetes cluster behind a load balancer.

My Configuration

Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration,
        IHostingEnvironment hostingEnvironment)
    {
        Configuration = configuration;
        HostingEnvironment = hostingEnvironment;
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddSignalR().AddRedis(options =>
        {
            options.Configuration = new ConfigurationOptions
            {
                EndPoints =
                    {
                        { ConfigurationManager.Configuration["settings:signalR:redis:host"], int.Parse(ConfigurationManager.Configuration["settings:signalR:redis:port"])}
                    },
                KeepAlive = 180,
                DefaultVersion = new Version(2, 8, 8),
                Password = ConfigurationManager.Configuration["settings:signalR:redis:password"]
            };
        });
        // ...
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/errors/general");
            app.UseHsts();
        }

        // nginx forward
        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

        app.UseSignalR(routes =>
        {
            routes.MapHub<StatisticsHub>("/hubs/myhub");
        });
    }
}

In order to verify that the connection to Redis server succeeded, I checking the output window of the Kastrel: enter image description here

Same behaviour (connected) found also on servers (2 replicas, not on development enviroment).

In order to verify that the Signalr is "really" using the Redis (not just connecting), I used redis-cli to connect the Redis server and found that:

enter image description here

From this I can understand that there are some "talks" on Redis.

I removed the website LoadBalancer (GCP) and deployed it agian. Now with Sticky-Session: ClientIP. This loadbalancer is routing requests to the different containers.

The only place that I didnt changed is the nginx configuration. I'm wrong?

The result

SignalR not working on the browser. These errors are from the browser console:

scripts.min.js:1 WebSocket connection to 'wss://site.com/hubs/myhub?id=VNxKLazEKr9FKM4GPZRDhA' failed: Error during WebSocket handshake: Unexpected response code: 404
scripts.min.js:1 Error: Failed to start the transport 'WebSockets': undefined
Error: Connection disconnected with error 'Error: Server returned handshake error: Handshake was canceled.'.
scripts.min.js:1 Error: Connection disconnected with error 'Error: Server returned handshake error: Handshake was canceled.'.
files.min.js:1 Uncaught (in promise) Error: Error connecting to signalR. Error= Error
...

Question

What I missed? What to check?

0

There are 0 best solutions below