SignalR 2 long polling "protocol" request times out when not ran locally

Thomas Florin picture Thomas Florin · Nov 8, 2013 · Viewed 8.1k times · Source

Currently I have an app that is very chatty and needs to be supported by a Singleton(See Code below). I upgraded to SignalR 2.0 and I followed the upgrade guide, but after I deploy it out to an environment, sometimes all requests for every "protocol" fail, and signalr breaks, and when it doesn't break then it is terribly slow to push notifications down to the client from the server, Maybe this has something to do with it using long polling? Here is what my server side code looks like.

Configuration Method in Owin Start up class

 var hubConfig = new HubConfiguration();
 hubConfig.EnableDetailedErrors = true;
 GlobalHost.DependencyResolver.UseSqlServer(ConfigurationManager.AppSettings["ConnectionString"].ToString());
 app.MapSignalR(hubConfig);

As you can see I am using an SQL Backplane. Here is what my Hub looks like

public class MyHub : Hub
{
    public void JoinGroup(int someId)
    {
        Groups.Add(Context.ConnectionId, someId.ToString());
    }

    public void LeaveGroup(int someId)
    {
        Groups.Remove(Context.ConnectionId, someId.ToString());
    }
}

Another point to make here is that I am using groups. Which may be part of the problem, I have noticed that groups seem to make things go slower, as if signalr is waiting for all users from the group to finish after it pushes out a notification. My Singleton looks like this.

public class Broadcaster
    {
        private readonly static Lazy<Broadcaster> _instance =
            new Lazy<Broadcaster>(() => new Broadcaster(GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients));
        private IHubConnectionContext _context;
        private Broadcaster(IHubConnectionContext context)
        {
            _context = context;
        }
        public static Broadcaster Instance
        {
            get { return _instance.Value; }
        }
        public void UpdateClient(int someId, int moreInfo)
        {
            _context.Group(someId.ToString()).Update(someId, moreInfo);
        }
    }

Finally these are the outputs from the logs on the client.

  • 16:37:25 GMT-0600 (Central Standard Time)] SignalR: Client subscribed to hub 'myhub'. 16:37:25 GMT-0600 (Central Standard Time)] SignalR: Negotiating with '/api/signalr/negotiate?connectionData=%5B%7B%22name%22%3A%22myhub%22%7D%5D&clientProtocol=1.3'.
  • then it attempts to connect to an SSE Endpoint and that fails...
  • 16:37:30 GMT-0600 (Central Standard Time)] SignalR: This browser supports SSE, skipping Forever Frame.
  • 16:37:31 GMT-0600 (Central Standard Time)] SignalR: Opening long polling request to...
  • 16:37:35 GMT-0600 (Central Standard Time)] SignalR: longPolling timed out when trying to connect.
  • 16:37:35 GMT-0600 (Central Standard Time)] SignalR: Aborted xhr request.

    (Error from subscribing to errors on the hub) SignalR error: Error: No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.

  • 16:37:35 GMT-0600(Central Standard Time)] SignalR: Stopping connection.
  • 16:37:35 GMT-0600 (Central Standard Time)] SignalR: Fired ajax abort async = true.

Any thoughts?

Answer

N. Taylor Mullen picture N. Taylor Mullen · Nov 8, 2013

So there's a TransportConnectTimeout now in 2.0.0 SignalR. It sounds like having your SQL backplane is slowing down the connect process resulting in your transports to timeout.

You can modify the TransportConnectTimeout on the server via:

GlobalHost.Configuration.TransportConnectTimeout = TimeSpan.FromSeconds(10);

Therefore whenever a client tries to connect it will abide by the new timeout.

You can also modify this value on the client. When modified the client takes it's TransportConnectTimeout and adds it to the servers and then uses the result as the timeout. Here's how to modify the client:

$.connection.hub.transportConnectTimeout = 3000;

If the server's TransportConnectTimeout is 5s that means the client will abide by an 8s timeout window when trying to connect.

You can choose to modify one of the values, or both of the values, it doesn't matter, whatever fits your needs!

Hope this helps!