Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HubConnection.Stop takes 30 seconds on Silverlight client #3102

Closed
yowl opened this issue Jun 28, 2014 · 9 comments
Closed

HubConnection.Stop takes 30 seconds on Silverlight client #3102

yowl opened this issue Jun 28, 2014 · 9 comments

Comments

@yowl
Copy link

yowl commented Jun 28, 2014

I attempt to close the SignalR connection before the users logs out of my silverlight client using this code and it takes 30 seconds to do so. I saw #2191 and maybe the fix for the .net client is not applied to the SIlverlight client?

Stop code which takes 30 seconds - this is not called from within an On method..

    void StopChat()
    {
        if (hubConn != null)
        {
            hubConn.Stop();
        }
    }
@DamianEdwards
Copy link
Member

Thanks, we'll take a look. If you can share any more information that may help us to reproduce the issue please do so.

@moozzyk
Copy link
Contributor

moozzyk commented Jul 25, 2014

Even though we send Abort request it is actually never sent by the HttpClient when using the portable HttpClient library. The 30 seconds is the default timeout we wait for the response to the Abort request. Until I find out why the underlying HttpClient never sends the Abort request you can use the Stop(TimeSpan) overload and provide a smaller timeout.

@moozzyk
Copy link
Contributor

moozzyk commented Jul 29, 2014

It looks that even though the SignalR client invokes HttpClient.SendAsync() the request is actually never sent to the server. I tracked it down to the BeginInvokeImpl method which calls NativeHost.Current.RuntimeHost.RaiseAsyncCallback (see the stack trace below) but the callback (which in this case is the InternalBeginGetResponse) is never invoked. Since from what I could see the InternalBeginGetResponse is responsible for sending the request the request is never sent and the InvokeImpl method is blocked infinitely waiting for the callback to complete.

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#

@moozzyk
Copy link
Contributor

moozzyk commented Jul 29, 2014

This is because of a deadlock. We block the thread waiting for the response to the abort request to the server. If the thread we are blocking happens to be the UI thread it will cause a dead lock since Silverlight wants to send the request on the UI thread.

@moozzyk
Copy link
Contributor

moozzyk commented Jul 29, 2014

@yowl - one way to work around this issue is to invoke .Stop on a non-UI thread - e.g.: await Task.Factory.StartNew(() => hubConnection.Stop()); another workaround would be to set the Stop timeout to 0 like this: hubConnection.Stop(new TimeSpan(0, 0, 0, 0)); - note that in this case the abort request will never be sent to the server.

@moozzyk moozzyk closed this as completed Jul 29, 2014
@moozzyk moozzyk reopened this Jul 29, 2014
@moozzyk
Copy link
Contributor

moozzyk commented Jul 29, 2014

Fixing #3067 will "fix" this issue.

moozzyk pushed a commit that referenced this issue Jul 31, 2014
(We wish him luck in /dev/null)

Fixes workitems #3067 and #3102
moozzyk pushed a commit that referenced this issue Jul 31, 2014
(We wish him luck in /dev/null)

Fixes workitems #3067 and #3102
moozzyk pushed a commit that referenced this issue Aug 4, 2014
(We wish him luck in /dev/null)

Fixes workitems #3067 and #3102
@moozzyk
Copy link
Contributor

moozzyk commented Aug 4, 2014

"Fixed" in 7358f1d - we no longer block to receive a response to abort request.

@moozzyk moozzyk added v3 and removed 3 - Working labels Aug 7, 2014
@moozzyk
Copy link
Contributor

moozzyk commented Aug 7, 2014

We had to revert the change since it introduced a couple of issues and races we were able to identify and possibly some we have not hit. It became apparent that the change is too risky. We will need to re-think the transport-connection interaction to fix this correctly and/or make the Stop call async.

@DamianEdwards
Copy link
Member

We'll look at this for v3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants