How to use SignalR on multiple servers?

Viewed 259

I have a chat app that I made with dotnet core, singalR, and react native. My chat is working well when I publish it on a single server. But when I get publish it in multiple servers by docker swarm. I get this error.

Unable to connect to the server with any of the available transports. WebSockets failed: Error: There was an error with the transport.

By this error message, the app is just sometimes working normally. When I leave the page and return back it is not working again.

I am using ubuntu server. I both aligned the versions of signalR on server and client. They are both using 5.0.3. I don't have proxy server in front of the app and I m using load balancing feature of docker swarm.

Configure Service

var tokenKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(opt =>
            {
                opt.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = tokenKey,
                    ValidateAudience = false, 
                    ValidateIssuer = false,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };
                opt.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];
                        var path = context.HttpContext.Request.Path;

                        if (!string.IsNullOrEmpty(accessToken))
                        {
                            if (path.StartsWithSegments("/chat")
                            || path.StartsWithSegments("/dialog"))
                            {
                                context.Token = accessToken;
                            }
                        }

                        return Task.CompletedTask;
                    }
                };
            });

Configure Void

app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.MapHub<ChatHub>("/chat", opt => { opt.Transports = HttpTransportType.WebSockets; });     
            endpoints.MapHub<DialogHub>("/dialog", opt => { opt.Transports =  HttpTransportType.WebSockets; }); 

        });
1 Answers

When scaling out SignalR to multiple servers, a shared data plane would be needed to manage distributed state, in addition to the network considerations.

As noted in the docs, Microsoft suggests either introducing a Redis backplane or delegating to their managed service, Azure SignalR.

An app that uses SignalR needs to keep track of all its connections, which creates problems for a server farm. Add a server, and it gets new connections that the other servers don't know about.

Having used Azure SignalR, it's fairly straightforward to integrate with an ASP.NET Core app. You then have offloaded all the overhead of managing connections from your app.

Related