Search code examples
asp.netjqueryazuresignalrsignalr-hub

Intermittent problems with SignalR Hubs (in the Cloud) callback from Server to Client method


So far, SignalR Hubs has been working perfectly with a locally hosted website in IIS 7.5 on my dev machine. I have the client making a signalr call to the server on a click event, then the server does a 20 second thread delay before sending a response back to the callback method on the client. This works consistently across all browsers. However, when I deploy my application to the Windows Azure Cloud, SignalR begins to have these intermittent problems. Specifically, there seems to be a problem with the server reaching the callback method on the client. I verified this by watching the network traffic in Chrome Dev Tools. I can clearly see the POST connection being made out by signalr. It sits in "pending" status for 20 seconds and then the POST successfully completes when the server responds back. However, the callback method (with a simple alert message) on the client-side doesn't always fire for some reason. NOTE: In my testing, I noticed some strange behavior that when the callback method is not firing, I could get it to fire by doing a normal download of a file (by using href = window.baseUrl + '/CloudStorage/DownloadZip?') and then clicking on the button that triggers the signalr. As I'm watching this in network traffic, somehow that window.baseUrl BOM command triggers the signalr to do a reconnect. Would appreciate any help!

EDIT: I am using IE 10, latest Chrome, and latest Firefox for all my testing. IE 10 seems to have the most issues with signalr when the app is in the cloud, which is a little strange to me since this is an MS product. Also, I'm using version 1.1.2 of SignalR.

Here are my code snippets:

SERVER SIDE:

[HubName("MultiFile")]
public class MultiFile : Hub
{      

    [HubMethodName("Send")]
    public void Send(string DocID)
    {
        System.Threading.Thread.Sleep(20000);

        // Call the addMessage method on caller client            
        Clients.Caller.addMessage(DocID);
    }

}

CLIENT SIDE:

        $('#dBtn').click(function () {
        var docIds = sceneLayoutService.getSelection();
        var href;
        var docIdsParam;
        if (docIds.length === 0) {               
            // signalr test code below
            // Proxy created on the fly          
            var test_connection = $.connection.MultiFile;

            // Declare a function on the MultiFile hub so the server can invoke it
            test_connection.client.addMessage = function (message) {
                alert(message);
            };

            // Start the connection
            $.connection.hub.start().done(function () {
                // Call the chat method on the server
                test_connection.server.Send("you need to select one!");
            });

            return false;
        }
        else if (docIds.length == 1) {
            docIdsParam = "docId=" + docIds;
            href = window.baseUrl + '/CloudStorage/Download?' + docIdsParam;
        }
        else {
            docIdsParam = jQuery.param(docIds.map(function (value) {
                //var parts = value.match(/[e[B|b]:\/\/[^\/]*\/\d*\/(\d*)/);
                //return { "name": "docIds", "value": parts[1] };
                return { "name": "docIds", "value": value };
            }));
            href = window.baseUrl + '/CloudStorage/DownloadZip?' + docIdsParam;
        }

        $(this).attr('href', href);
        return true;
    });

LIST OF PACKAGES:

        <?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Company.CONNECT.Analytics.eFWrapper" version="1.0.0.1" targetFramework="net40" />
  <package id="Company.CONNECT.Analytics.Logging" version="1.0.0.11" targetFramework="net40" />
  <package id="Company.CONNECT.Web" version="1.1.0.12" targetFramework="net40" />
  <package id="Castle.Core" version="2.5.2" targetFramework="net40" />
  <package id="Castle.Core-log4net" version="2.5.2" targetFramework="net40" />
  <package id="Castle.Windsor" version="2.5.4" targetFramework="net40" />
  <package id="Castle.Windsor-log4net" version="2.5.2" targetFramework="net40" />
  <package id="CommonServiceLocator" version="1.0" targetFramework="net40" />
  <package id="EnterpriseLibrary.Common" version="5.0.505.0" targetFramework="net40" />
  <package id="EnterpriseLibrary.WindowsAzure.Configuration" version="5.0.1118.2" targetFramework="net40" />
  <package id="EntityFramework" version="4.1.10331.0" targetFramework="net40" />
  <package id="HtmlAgilityPack" version="1.4.6" targetFramework="net40" />
  <package id="jQuery" version="2.0.2" targetFramework="net40" />
  <package id="jQuery.UI.Combined" version="1.10.3" targetFramework="net40" />
  <package id="jQuery.Validation" version="1.8.0" targetFramework="net40" />
  <package id="jQuery.vsdoc" version="1.5.1" targetFramework="net40" />
  <package id="log4net" version="1.2.10" targetFramework="net40" />
  <package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.Providers" version="1.1" targetFramework="net40" />
  <package id="Microsoft.AspNet.Providers.Core" version="1.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.SignalR" version="1.1.2" targetFramework="net40" />
  <package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net40" />
  <package id="Microsoft.AspNet.SignalR.JS" version="1.1.2" targetFramework="net40" />
  <package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net40" />
  <package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net40" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.0.0" targetFramework="net40" />
  <package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
  <package id="Microsoft.Data.Edm" version="5.5.0" targetFramework="net40" />
  <package id="Microsoft.Data.OData" version="5.5.0" targetFramework="net40" />
  <package id="Microsoft.IdentityModel" version="6.1.7600.16394" targetFramework="net40" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net40" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
  <package id="Microsoft.WindowsAzure.ConfigurationManager" version="2.0.1.0" targetFramework="net40" />
  <package id="Modernizr" version="2.6.2" targetFramework="net40" />
  <package id="Newtonsoft.Json" version="4.5.11" targetFramework="net40" />
  <package id="Owin" version="1.0" targetFramework="net40" />
  <package id="Pkcs12ProtectedConfigurationProvider" version="1.0.1" targetFramework="net40" />
  <package id="RequireJS" version="2.1.8" targetFramework="net40" />
  <package id="SevenZipSharp" version="0.64" targetFramework="net40" />
  <package id="SlowCheetah" version="2.5.5" targetFramework="net40" />
  <package id="System.Spatial" version="5.5.0" targetFramework="net40" />
  <package id="System.Web.Providers" version="1.2" targetFramework="net40" />
  <package id="Unity" version="2.1.505.2" targetFramework="net40" />
  <package id="Unity.Interception" version="2.1.505.2" targetFramework="net40" />
  <package id="WebGrease" version="1.1.0" targetFramework="net40" />
  <package id="WindowsAzure.Storage" version="2.0.5.1" targetFramework="net40" />
  <package id="WindowsAzure.Storage" version="2.0.6.0" targetFramework="net40" />
</packages>

Solution

  • It turns out there are 2 Web Role instances running in my Windows Azure configuration. When there are multiple Azure instances running, a "backplane" needs to be used since we have no control over which instance the Azure Load Balancer chooses. This is why the messages sent back from the server to client were failing 50% of the time.

    http://www.asp.net/signalr/overview/performance-and-scaling/scaleout-in-signalr