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

Viewed 104

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'
1 Answers

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.

Another thing to note is that the method WithAutomaticReconnect has [0, 2000, 10000, 30000, null] as the default values. Meaning that, if the client gets disconnected from the server, it will wait 0, 2, 10 and 30 seconds respectively before trying to reconnect again. If it doesnt get reconnected at that point it will stop trying. If you want to have your client trying to reconnect infinitely you have to create your own retry policy:

public class RetryPolicyLoop : IRetryPolicy
{
    private const int ReconnectionWaitSeconds = 5;

    public TimeSpan? NextRetryDelay(RetryContext retryContext)
    {
        return TimeSpan.FromSeconds(ReconnectionWaitSeconds);
    }
}

And in your HubConnectionBuilder:

.WithAutomaticReconnect(new RetryPolicyLoop())

That way your client will try to reconnect infinitely (waiting 5 seconds after each failed attempt).

EDIT:

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

Related