SignalR 2 - 当多个集线器实例时,并非客户端从服务器发送的所有消息

时间:2014-03-19 16:37:01

标签: angularjs azure signalr signalr-hub

修改

我一直在做一些额外的测试,这似乎只发生在我运行多个托管SignalR集线器的Web角色实例时(我正在使用天蓝色服务总线背板)。当我运行集线器的单个实例时,我看到所有消息都通过客户端传递。当我运行多个实例时,我会遇到这些症状:

  • 从服务器登录表示已发送所有邮件
  • 从客户端登录表示只收到了一些邮件
  • 使用wireshark查看服务器流量,同时使用azure远程访问云服务仅捕获客户端收到的消息

我怀疑客户端是否与Web角色的单个实例建立了连接,并且当消息恰好来自客户端未连接的Web角色时,即使客户端连接到该角色,客户端也无法接收到该角色。广播到正确的SignalR连接。

在运行网站中托管的SignalR集群的多个实例时,其他任何人都遇到了丢失邮件的问题?有没有解决这个问题的方法?


我通过来自javascript客户端的API调用启动了一个异步进程,该调用完成了一个或多个通过我们的SignalR中心发送回该客户端的消息。似乎并非所有从SignalR中心发送的消息都被javascript客户端接收。以下是我收到的记录消息的流程:

  1. 客户端连接到我们的SignalR中心,然后立即调用一个订阅方法,该方法将当前连接ID与我们的内部用户标识符相关联:

    • Websocket打开
    • 现在监控保持活动状态,警告超时为13333.333333333332,连接丢失超时为20000.
    • 在“EventHub”集线器上触发客户端集线器事件“已订阅”
    • 客户订阅了事件中心:5539368b-5f82-48bd-8ed9-2c5bed3caefa [这是指示后端将给定的连接ID与用户ID相关联]
  2. 我启动后端进程,导致两条消息被发送回此客户端。从SignalR集线器内部进行日志记录表明正在发送两条消息(消息列出了与给定内部用户ID相关的所有连接 - 我的缓存中的旧连接尚未清除):

    • 事件中枢广播控制动作更新到用户124,用于连接上的控制动作120aaea44a-7810-45b5-8119-3ff1fe613d63,4be9ca16-1e31-42bf-91db-798b757a381c,5f9f9962-4f8b-4712-929e-c943e28ca91f,de7135ba- 4e16-4e9e-9c38-e8f78ed59636,82e900d1-005e-4bff-95d0-3737632b4671,0cc273f9-04aa-4570-8cd7-993876219e52,2b6db0f7-ab0c-41d3-beb5-3b312107a923,5539368b-5f82-48bd-8ed9-2c5bed3caefa [注意上面的连接ID包含在列表中]
    • 事件中枢广播控制动作更新到用户124,用于连接上的控制动作128 5aaea44a-7810-45b5-8119-3ff1fe613d63,4be9ca16-1e31-42bf-91db-798b757a381c,5f9f9962-4f8b-4712-929e-c943e28ca91f,de7135ba- 4e16-4e9e-9c38-e8f78ed59636,82e900d1-005e-4bff-95d0-3737632b4671,0cc273f9-04aa-4570-8cd7-993876219e52,2b6db0f7-ab0c-41d3-beb5-3b312107a923,5539368b-5f82-48bd-8ed9-2c5bed3caefa [注意上面的连接ID包含在列表中]
  3. 在客户端上,我正在记录由于发送消息而调用该方法时,我看到:

    • 从事件中心收到了controlActionUpdated消息,型号为:controlActionId 120
  4. 有时,客户端会收到从集线器发送的所有邮件,但更常见的是,它缺少一两个。相关的代码段如下:

    客户端:

    我们在angularjs中使用广义事件服务。事件消费者连接并订阅事件列表,如下所示:

    eventing.initialize(['controlActionUpdated', 'subscribed']);

    服务如下:

    var cn;
    var hubProxy;
    var eventsToHandle = [];
    
    var initialize = function(events){
        for(var index = 0; index < events.length; index++){
            if(eventsToHandle.indexOf(events[index]) == -1){
                eventsToHandle.push(events[index]);
            }
        }
        connect();
    }
    
    //call this to connect to the eventing hub and set up client-side receiving methods
    var connect = function(){
        cn = $.hubConnection('https://events.xxx.com/');
        cn.logging = true;
    
        hubProxy = cn.createHubProxy('eventHub');
    
        //subscribe to all events currently indicated to be handled
        for(var index = 0; index < eventsToHandle.length; index++){
            listen(eventsToHandle[index]);
        }
    
        hubProxy.on('subscribed', function (model) {
            console.log('Client subscribed to event hub: ' + model);
        });
    
        cn.qs = { "optiAuthToken" : authentication.getAuthToken() };
        cn.start().done(function(){
            //subscribe to events for this specific user
            hubProxy.invoke('subscribe');
            $rootScope.$broadcast('connectedToHub');
        });
    }
    
    
    var listen = function(eventName){
        hubProxy.on(eventName, function(model){
            $rootScope.$broadcast(eventName, model);
        });
    }
    

    上述$rootScope.$broadcast(eventName, model);电话的接收方式为:

    $scope.$on('controlActionUpdated', function (event, model) {
        console.log('received controlActionUpdated message from event hub with model: controlActionId ' + model.controlActionId);
        [further code omitted]
    

    服务器

    此方法调用缓存以获取executionUserID的连接列表。如果它找到至少一个,它会向该连接列表发送一条消息。

    public async Task MyControlActionUpdated(ControlActionEventModel model, int executingUserID)
    {
        EventingConnectionDetails[] currentConnections = await cache.GetCurrentEventHubConnections(executingUserID);
        if (currentConnections.Length > 0)
        {
            Trace.TraceInformation("event hub broadcasting control action updated to user {0} for control action {1} on connections {2}",
                executingUserID, model.controlActionId, string.Join(", ", currentConnections.Select(c => c.ConnectionID).Distinct()));
            Clients.Clients(currentConnections.Select(c => c.ConnectionID).Distinct().ToList()).controlActionUpdated(model);
        }
        else
        {
            Trace.TraceError("attempt to broadcast control action updated to user {0} for control action {1} failed due to no connections",
                executingUserID, model.controlActionId);
        }
    

    }

    我环顾四周寻找其他人抱怨客户端丢失了来自服务器的消息但没有发现任何消息。有没有人知道为什么从服务器发送的消息记录不会记录在客户端上?

    我正在使用服务总线背板在Azure中的Web角色中托管的SignalR 2.0。客户端是AngularJS版本1.2.14。

1 个答案:

答案 0 :(得分:1)

问题是由于我的配置不正确,服务总线背板实际上没有工作(我首先在我的依赖解析器上调用UseServiceBus,然后将依赖解析器设置为我的统一解析器用于DI)。

自我注意:在尝试深入挖掘之前,首先检查通过服务总线主题的流量。 :)