Signalr: HubConnection.Stop prend 30 secondes sur le client Silverlight

Créé le 28 juin 2014  ·  9Commentaires  ·  Source: SignalR/SignalR

J'essaie de fermer la connexion SignalR avant que les utilisateurs ne se déconnectent de mon client silverlight à l'aide de ce code et cela prend 30 secondes. J'ai vu https://github.com/SignalR/SignalR/issues/2191 et peut-être que le correctif pour le client .net n'est pas appliqué au client SIlverlight?

Code d'arrêt qui prend 30 secondes - il n'est pas appelé à partir d'une méthode On.

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

Commentaire le plus utile

@yowl - une façon de contourner ce problème est d'appeler .Stop sur un thread non-UI - par exemple: await Task.Factory.StartNew(() => hubConnection.Stop()); une autre solution de contournement serait de définir le délai d'arrêt à 0 comme ceci: hubConnection.Stop(new TimeSpan(0, 0, 0, 0)); - notez que dans ce cas, la demande d'abandon ne sera jamais envoyée au serveur.

Tous les 9 commentaires

Merci, nous allons jeter un oeil. Si vous pouvez partager d'autres informations susceptibles de nous aider à reproduire le problème, veuillez le faire.

Même si nous envoyons une demande d'abandon, elle n'est en fait jamais envoyée par HttpClient lors de l'utilisation de la bibliothèque portable HttpClient. Les 30 secondes sont le délai d'expiration par défaut, nous attendons la réponse à la demande d'abandon. Jusqu'à ce que je découvre pourquoi le HttpClient sous-jacent n'envoie jamais la demande Abort, vous pouvez utiliser la surcharge Stop(TimeSpan) et fournir un délai d'expiration plus court.

Il semble que même si le client SignalR invoque HttpClient.SendAsync() la requête n'est en fait jamais envoyée au serveur. Je l'ai suivi jusqu'à la méthode BeginInvokeImpl qui appelle NativeHost.Current.RuntimeHost.RaiseAsyncCallback (voir la trace de la pile ci-dessous) mais le rappel (qui dans ce cas est le InternalBeginGetResponse ) n'est jamais appelé. Puisque d'après ce que j'ai pu voir, InternalBeginGetResponse est responsable de l'envoi de la demande, la demande n'est jamais envoyée et la méthode InvokeImpl est bloquée indéfiniment en attendant que le rappel soit terminé.

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#

C'est à cause d'une impasse. Nous bloquons le thread en attente de la réponse à la demande d'abandon adressée au serveur. Si le thread que nous bloquons est le thread d'interface utilisateur, cela entraînera un blocage mort car Silverlight souhaite envoyer la demande sur le thread d'interface utilisateur.

@yowl - une façon de contourner ce problème est d'appeler .Stop sur un thread non-UI - par exemple: await Task.Factory.StartNew(() => hubConnection.Stop()); une autre solution de contournement serait de définir le délai d'arrêt à 0 comme ceci: hubConnection.Stop(new TimeSpan(0, 0, 0, 0)); - notez que dans ce cas, la demande d'abandon ne sera jamais envoyée au serveur.

La correction # 3067 "résoudra" ce problème.

"Corrigé" dans 7358f1d - nous ne bloquons plus pour recevoir une réponse à une demande d'abandon.

Nous avons dû annuler le changement car il a introduit quelques problèmes et races que nous avons pu identifier et peut-être que nous n'avons pas touché. Il est devenu évident que le changement était trop risqué. Nous devrons repenser l'interaction transport-connexion pour résoudre ce problème correctement et / ou rendre l'appel d'arrêt asynchrone.

Nous allons regarder cela pour la v3

Cette page vous a été utile?
0 / 5 - 0 notes