Signalr: HubConnection.Stop leva 30 segundos no cliente Silverlight

Criado em 28 jun. 2014  ·  9Comentários  ·  Fonte: SignalR/SignalR

Tento fechar a conexão SignalR antes que os usuários façam logout do meu cliente silverlight usando este código e leva 30 segundos para fazer isso. Vi https://github.com/SignalR/SignalR/issues/2191 e talvez a correção para o cliente .net não seja aplicada ao cliente SIlverlight?

Código de parada que leva 30 segundos - não é chamado de dentro de um método On ..

    void StopChat()
    {
        if (hubConn != null)
        {
            hubConn.Stop();
        }
    }
.NET Bug

Comentários muito úteis

@yowl - uma maneira de contornar esse problema é invocar .Stop em um thread que não seja da IU - por exemplo: await Task.Factory.StartNew(() => hubConnection.Stop()); outra solução alternativa seria definir o tempo limite de parada como 0 assim: hubConnection.Stop(new TimeSpan(0, 0, 0, 0)); - observe que, neste caso, a solicitação de cancelamento nunca será enviada ao servidor.

Todos 9 comentários

Obrigado, vamos dar uma olhada. Se você puder compartilhar mais informações que possam nos ajudar a reproduzir o problema, faça-o.

Embora enviemos uma solicitação de aborto, ela nunca é enviada pelo HttpClient ao usar a biblioteca portátil HttpClient. Os 30 segundos são o tempo limite padrão que esperamos pela resposta à solicitação de aborto. Até eu descobrir por que o HttpClient subjacente nunca envia a solicitação Abort, você pode usar a sobrecarga Stop(TimeSpan) e fornecer um tempo limite menor.

Parece que, embora o cliente SignalR invoque HttpClient.SendAsync() a solicitação nunca é enviada ao servidor. Eu rastreei o método BeginInvokeImpl que chama NativeHost.Current.RuntimeHost.RaiseAsyncCallback (veja o rastreamento de pilha abaixo), mas o retorno de chamada (que neste caso é InternalBeginGetResponse ) nunca é invocado. Uma vez que pelo que pude ver, InternalBeginGetResponse é responsável por enviar a solicitação, a solicitação nunca é enviada e o método InvokeImpl é bloqueado infinitamente esperando o retorno de chamada ser concluído.

System.Windows.RuntimeHost.dll!System.Windows.RuntimeHost.ManagedRuntimeHost.RaiseAsyncCallback(System.IntPtr pDelegate, bool useFastPath) Line 191 C# System.Windows.dll!System.Windows.Threading.Dispatcher.BeginInvokeImpl(System.Windows.Threading.DispatcherPriority priority, bool useFastPath, System.Delegate d, object[] args) Line 105 + 0x30 bytes C# System.Windows.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, bool useFastPath, System.Delegate d, object[] args) Line 174 + 0x3d bytes C# System.Windows.dll!System.Net.Browser.AsyncHelper.BeginOnUI(System.Net.Browser.BeginMethod beginMethod, System.AsyncCallback callback, object state) Line 142 + 0x4e bytes C# System.Windows.dll!System.Net.Browser.BrowserHttpWebRequest.BeginGetResponse(System.AsyncCallback callback, object state) Line 342 + 0x27 bytes C# System.Net.Http!System.Net.Http.HttpWebRequest.BeginGetResponse(System.AsyncCallback callback, object state) Line 138 + 0x22 bytes C# System.Net.Http!System.Net.Http.HttpClientHandler.StartGettingResponse(System.Net.Http.HttpClientHandler.RequestState state) Line 910 + 0x2b bytes C# System.Net.Http!System.Net.Http.HttpClientHandler.GetRequestStreamCallback.AnonymousMethod__8(System.Threading.Tasks.Task task) Line 883 + 0x15 bytes C# mscorlib.dll!System.Threading.Tasks.ContinuationTaskFromTask.InnerInvoke() Line 58 + 0xc bytes C# mscorlib.dll!System.Threading.Tasks.Task.Execute() Line 2437 + 0xb bytes C# mscorlib.dll!System.Threading.Tasks.Task.ExecutionContextCallback(object obj) Line 2792 + 0x9 bytes C# mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 417 + 0xd bytes C# mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Line 2763 C# mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Line 2695 + 0x1b bytes C# mscorlib.dll!System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(System.Threading.Tasks.Task task, bool taskWasPreviouslyQueued) Line 104 + 0xb bytes C# mscorlib.dll!System.Threading.Tasks.TaskScheduler.TryRunInline(System.Threading.Tasks.Task task, bool taskWasPreviouslyQueued) Line 217 + 0x12 bytes C# mscorlib.dll!System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(System.Threading.Tasks.Task task, bool needsProtection) Line 258 + 0xe bytes C# mscorlib.dll!System.Threading.Tasks.StandardTaskContinuation.Run(System.Threading.Tasks.Task completedTask, bool bCanInlineContinuationTask) Line 323 + 0x53 bytes C# mscorlib.dll!System.Threading.Tasks.Task.ContinueWithCore(System.Threading.Tasks.Task continuationTask, System.Threading.Tasks.TaskScheduler scheduler, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskContinuationOptions options) Line 4585 + 0x12 bytes C# mscorlib.dll!System.Threading.Tasks.Task.ContinueWith(System.Action<System.Threading.Tasks.Task> continuationAction, System.Threading.Tasks.TaskScheduler scheduler, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskContinuationOptions continuationOptions, ref System.Threading.StackCrawlMark stackMark) Line 3834 C# mscorlib.dll!System.Threading.Tasks.Task.ContinueWith(System.Action<System.Threading.Tasks.Task> continuationAction, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskContinuationOptions continuationOptions, System.Threading.Tasks.TaskScheduler scheduler) Line 3799 + 0x1b bytes C# System.Net.Http!System.Net.Http.HttpUtilities.ContinueWithStandard(System.Threading.Tasks.Task task, System.Action<System.Threading.Tasks.Task> continuation) Line 49 + 0x4b bytes C# System.Net.Http!System.Net.Http.HttpClientHandler.GetRequestStreamCallback(System.IAsyncResult ar) Line 866 + 0x7d bytes C# System.Windows.dll!System.Net.Browser.BrowserHttpWebRequest.InvokeGetRequestStreamCallback.AnonymousMethod__12(object state2) Line 786 + 0x11 bytes C# mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state) Line 1253 + 0xb bytes C# mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) Line 417 + 0xd bytes C# mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() Line 1230 + 0x22 bytes C# mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Line 807 C# mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Line 1145 + 0x5 bytes C#

Isso ocorre por causa de um impasse. Bloqueamos o thread que aguarda a resposta ao pedido de aborto ao servidor. Se o encadeamento que estamos bloqueando for o encadeamento de IU, isso causará um bloqueio morto, pois o Silverlight deseja enviar a solicitação no encadeamento de IU.

@yowl - uma maneira de contornar esse problema é invocar .Stop em um thread que não seja da IU - por exemplo: await Task.Factory.StartNew(() => hubConnection.Stop()); outra solução alternativa seria definir o tempo limite de parada como 0 assim: hubConnection.Stop(new TimeSpan(0, 0, 0, 0)); - observe que, neste caso, a solicitação de cancelamento nunca será enviada ao servidor.

A correção do número 3067 "corrigirá" esse problema.

"Corrigido" em 7358f1d - não bloqueamos mais o recebimento de uma resposta à solicitação de aborto.

Tivemos que reverter a mudança, pois ela introduziu alguns problemas e corridas que pudemos identificar e, possivelmente, alguns que não atingimos. Ficou claro que a mudança é muito arriscada. Teremos de repensar a interação de conexão de transporte para corrigir isso e / ou tornar a chamada de parada assíncrona.

Veremos isso para a v3

Esta página foi útil?
0 / 5 - 0 avaliações