No1Lives4Ever
No1Lives4Ever

Reputation: 6883

Signalr-Redis "No Connection with that ID"

Background

I have a website which deployed on the Google Cloud. This website written with asp.net core (v2.2) and signalr.

My application architecture is that I have two machines, running Linux, serving same site. The site served by Kastrel (localhost) and wrapped by nginx (for the outside network). I have cloud Load Balancer which spliting the trafic between those two instances. The LB defined to split the traffic by session-affinity.

I defined SignalR to use Redis in order to work well in the multiple instances enviroment.

My startup.cs code:

var redisCs = ConfigurationOptions.Parse("REDIS CS");
services.AddSignalR().AddRedis(options =>
{
    options.ConnectionFactory = async writer =>
    {
        var connection = await ConnectionMultiplexer.ConnectAsync(redisCs, writer);
        return connection;
    };
    options.Configuration.ClientName = "Main-website-Signalr";
});

The Problem

When I testing it, some of the times it's working and on the other time - its not.

When it failed, I see this logs on browser console:

WebSocket connection to 'wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg' failed: Error during WebSocket handshake: Unexpected response code: 404

On my browser "Network" tab I see that the browser try to communicate with the address wss://mysite.com/hubs/myhub?id=R_Zmaew-lRN_r2d_c-xOyg and get 404 response.

My Investigation

I worried that the nginx is blocking the connection somehow, so I decide to connect with the Kestrel without any mediator. I ssh'ed into the machine and run this command:

$ curl 127.0.0.1:5000/hubs/businesses?id=Tta4PmrjMrzHBHa8CT0SPQ -v
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /hubs/myhub?id=Tta4PmrjMrzHBHa8CT0SPQ HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.52.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Date: Wed, 05 Jun 2019 06:26:09 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
<
* Curl_http_done: called premature == 0
* Connection #0 to host 127.0.0.1 left intact
No Connection with that ID

So, I got 404 error - same like I got on from the browser. I guess now that no-one is blocking the connection somehow. It just something with the SignalR configuration is broken.

Why the SignalR can find the connection?

Is that matter for which machine I logged in? the connection isn't passed via Redis somehow?

Upvotes: 4

Views: 7075

Answers (1)

Brennan
Brennan

Reputation: 1933

When you have multiple server instances behind a single load-balancer you need to have sticky sessions enabled, meaning a unique client will only ever connect to a single machine.

You can see some info about the Redis backplane in https://learn.microsoft.com/en-us/aspnet/core/signalr/scale?view=aspnetcore-2.2#redis-backplane

SignalR is a protocol and part of that protocol means that a connection ID will be created on the server during "negotiate". This means you can't just randomly curl the endpoint with an ID because curl doesn't understand the SignalR protocol.

You can read more about the protocol if you're interested at https://github.com/aspnet/AspNetCore/tree/master/src/SignalR/docs/specs

Upvotes: 5

Related Questions