SignalR LongPolling multiple Groups.Adicionar para um único cliente Exception

9

Eu tenho lutado com isso por um tempo. Estamos usando o mais recente SignalR 2.0.3. O problema acontece quando adicionamos vários grupos SignalR. A exceção só é lançada quando várias adições acontecem do mesmo connectionId com nomes de grupos diferentes. A exceção só é lançada se o transporte LongPolling estiver selecionado. A exceção só é lançada se você adicionar 6 ou mais nomes de grupos exclusivos, 5 ou menos, e isso funciona bem.

Veja um exemplo simplificado:

Index.cshtml:

    @model Int32?
    <!DOCTYPE html>
    <head>
        <title></title>
<script src="@Url.Content("~/Scripts/jquery.min.js")" type="text/javascript"/>
<script src="@Url.Content("~/Scripts/jquery.signalR-2.0.3.min.js")"
    type="text/javascript" />
<script src="@Url.Content("~/signalr/hubs")" type="text/javascript"/>
    </head>

    <script>
        _testHub = $.connection.testHub;
        _testHub.client.sayHello = sayHello;
        $.connection.hub.start({ transport: 'longPolling' })
            .done(function() {
                addAllGroups();
            });

        function sayHello(aMessage, aGroupName) {
            console.info("GroupName: " + aGroupName 
    + " Message Sent:" + aMessage);
        };

        function addAllGroups() {
            for (var i = 0; 
              i < @(Model.HasValue ? Model.Value : 1 ); i++) {
                  addToGroupAndBroadcast(i);
            }
        };

        function addToGroupAndBroadcast(aGroupName) {
            _testHub.server.addToGroupAndBroadcast(aGroupName)
                .fail(function (desc) {
                    console.info("Error: " + desc);
                });
        };

    </script>

SignalRTestController.cs:

using System;
using System.Web.Mvc;


namespace Instrumar.ProductionDashboard.Controllers
{
    public class SignalRTestController : Controller
    {
        #region Public Members

        public ActionResult Index()
        {
            return View((int?)Convert.ToInt32(Request.Url.Segments[4]));
        }

        #endregion
    }
}

TestHub.cs:

using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;


namespace Instrumar.ProductionDashboard.Hubs
{
    public class TestHub : Hub
    {
        #region Public Members

        public void AddToGroupAndBroadcast(string aGroupName)
        {
            GlobalHost.ConnectionManager.GetHubContext<TestHub>().Groups.Add(Context.ConnectionId, aGroupName).Wait();
            Clients.Group(aGroupName).sayHello("Hello", aGroupName);
        }

        #endregion
    }
}

Startup.cs:

using Microsoft.AspNet.SignalR;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRChat.Startup))]
namespace SignalRChat
{

    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var lHubConfiguration = new HubConfiguration {EnableDetailedErrors = true};
            app.UseErrorPage();
            app.MapSignalR(lHubConfiguration);
        }
    }
}

O controlador usa um inteiro como entrada, que é o número de Add's a fazer. Por exemplo, se você ligar:

link um grupo.Add funciona bem link dois grupos.Adicionar funciona bem link três grupos.Adicionar funciona bem link quatro grupos.Adicionar funciona bem link cinco grupos.Adicionar funciona bem link seis grupos.Adicione quebrado link sete grupos.Adicione quebrado link oito grupos.Adicione quebrado link nove grupos.Adicione quebrado link dez grupos.Adicione quebrado

...

Quando digo quebrado, recebo de volta um "System.Threading.Tasks.TaskCanceledException" em TestHub.cs na linha que aguarda a conclusão da tarefa. Tudo funciona bem com ServerSentEvents, mas para LongPolling o problema existe. O que estou fazendo de errado? Não posso ter mais de 5 grupos SignalR com LongPolling? Ajude-me! :)

Atualização: colocar uma suspensão de 1 milissegundo usando setTimeout entre as chamadas do cliente corrigiu o problema. Isso parece aliviar o número de conexões pendentes na guia de rede. Talvez algo aconteça com a capacidade de adicionar a um grupo quando você atinge o limite de conexão do navegador único. Seria bom saber exatamente porque isso não funciona.

    
por Adam 12.06.2014 в 21:10
fonte

2 respostas

2

Você pode ter mais de 5 grupos com sondagens longas, mas será preciso resolver o problema de conexão não adicionando a grupos em um loop.

A tarefa retornada de Groups.Add somente é concluída quando recebe uma mensagem ACK do barramento de mensagens, indicando que a mensagem para o cliente (notificando o grupo adicionar) foi enviada. Se houver mais de 5 (ou qualquer número que seja imposto pelo navegador) solicitações pendentes de AJAX vinculadas à chamada addToGroupAndBroadcast do cliente, a mensagem para o cliente não poderá ser enviada. Se você anexar um callback feito à sua chamada de cliente:

_testHub.server.addToGroupAndBroadcast(groupName).done(function() {
    console.log("complete");
});

você verá a primeira chamada concluída quase que imediatamente.

É quando a primeira chamada Groups.Add retorna. A mensagem para sayHello não é mais enviada porque exigiria outra solicitação de pesquisa aberta, que o cliente está criando, mas não será manipulada, pois há várias outras solicitações pendentes do cliente que foram enfileiradas primeiro (e estão todos esperando addToGroupAndBroadcast para completar).

Então, após a primeira chamada para Groups.Add, o servidor não pode enviar nada ao cliente, o MessageHub não pode enviar seu ACK, o que resolveria as promessas Groups.Add restantes. Como resultado, o TaskCanceledException é lançado para essas tarefas devido a um tempo limite.

Como solução alternativa, sugiro criar um método de hub que aceite uma matriz de nomes de grupos:

public async Task AddToGroups(string[] names)
{
    foreach (var name in names)
    {
        await Groups.Add(Context.ConnectionId, name);
        Clients.Group(name).sayHello("Hello", name);
    }
}
    
por Lars Höppner 22.06.2014 / 15:51
fonte
0

Parece que há um problema relacionado que foi corrigido aqui link . Se é isso, você teria que puxar o código e recompilar sua própria DLL. Além disso, seu bug também pode ser causado por um tempo limite.

Isso também pode ser relevante para o seu problema:

  

... porque o ID de conexão que você está tentando   remove pode não estar mais disponível. Nesse caso,   TaskCanceledException é lançada após o tempo limite da solicitação.

link

    
por user1477388 17.06.2014 / 15:04
fonte