Search code examples
c#websocketsignalrkubernetes-ingressasp.net-core-signalr

Advantage or disadvantage when enabling SkipNegotation in SignalR (.net core) when using with aws eks


We are using AWS kubernetes cluster (EKS) with an ALB/Ingress and redis-cache for signalr connections. If we have a replicaset of 3, connecting to the services throws randomly a 404 error. When setting the options:

SkipNegotiation = true
Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets

Everything seems to work. I could not find any disadvantages of setting SkipNegotation to true. But could not find whether this has any side effects (there must be a reason it is set to false by default).

Could setting SkipNegotation to true cause any further problems?

Sample code that is working:

Console.WriteLine("Start");
HubConnection connection = new HubConnectionBuilder()
    .WithUrl("https://<url>/api/v1/taskboard", o =>
    {
        o.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
        o.SkipNegotiation = true;
    })
    .WithAutomaticReconnect()
    .Build();

await connection.StartAsync();


connection.On<string>("ReceiveMessage", message =>
{
    Console.WriteLine(message);
});

for (int i = 0; i < 20; i++)
{
    await connection.InvokeAsync("SendMessage", $"Hello {i}");
    await Task.Delay(55);
}

await connection.StopAsync();
await connection.DisposeAsync();

EDIT

Those settings has been added to the ingress:

alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:......
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS":443}]'
alb.ingress.kubernetes.io/ssl-redirect: '443'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/subnets: subnet-..., subnet-...
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=600
alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true,stickiness.lb_cookie.duration_seconds=600
alb.ingress.kubernetes.io/healthcheck-path: /HealthCheck
alb.ingress.kubernetes.io/healthcheck-port: '80'

Solution

  • The main reason to use SkipNegotiation is to avoid using sticky sessions. When you want to establish a connection with the SignalR server, the client sends a post request to the server, and the connection wont be established until the client receives a response from the server:

    Client request:

    {
       "connectionId":"807809a5-31bf-470d-9e23-afaee35d8a0d",
       "availableTransports":[
       {
          "transport": "WebSockets",
          "transferFormats": [ "Text", "Binary" ]
        },
        {
          "transport": "ServerSentEvents",
          "transferFormats": [ "Text" ]
        },
        {
          "transport": "LongPolling",
          "transferFormats": [ "Text", "Binary" ]
        }
        ]
    }
    

    Server response:

    {
       "url": "https://myapp.com/chat",
       "accessToken": "accessToken"
    }
    

    To avoid using sticky sessions, the client needs to skip negotiation but is restricted to only using websockets.

    Source: https://github.com/aspnet/SignalR/blob/release/2.2/specs/TransportProtocols.md