question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

StorageExtendedErrorInformation.ReadFromStream causing deadlocks in .net core asp.net application

See original GitHub issue

So, let me preface this by saying this is the first time I have ever used WinDBG and I’m kind of flying by the pants with this.

Our asp.net core application in production writes to blob storage (via appendblobs) every request for logging. We log specially formatted logs containing information about each request, parameters (with passwords redacted), exceptions, user information, etc…

The asp.net core application can go for over a week without issues and suddenly one instance on Azure will start hanging requests and returning 502s. Looking at the process details the dotnet.exe process is up to 700+ threads.

I took memory dumps via procmon, loaded sos, and ran clrstack on all the threads. Every thread I looked all had the exact same stack trace:

2d67e5f4 7728081c [GCFrame: 2d67e5f4] 
2d67e690 7728081c [HelperMethodFrame_1OBJ: 2d67e690] System.Threading.Monitor.ObjWait(Boolean, Int32, System.Object)
2d67e710 72233253 System.Threading.Monitor.Wait(System.Object, Int32, Boolean)
2d67e720 7223326c System.Threading.Monitor.Wait(System.Object, Int32)
2d67e724 722eadf3 System.Threading.ManualResetEventSlim.Wait(Int32, System.Threading.CancellationToken)
2d67e778 722ba6dc System.Threading.Tasks.Task.SpinThenBlockingWait(Int32, System.Threading.CancellationToken)
2d67e7b8 722ba5a9 System.Threading.Tasks.Task.InternalWait(Int32, System.Threading.CancellationToken)
2d67e814 722f8ba6 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
2d67e820 724550c9 System.Runtime.CompilerServices.TaskAwaiter`1[[System.Int32, System.Private.CoreLib]].GetResult()
2d67e828 6fc85890 System.Net.Http.WinHttpResponseStream.Read(Byte[], Int32, Int32)
2d67e844 6fc78c80 System.Net.Http.DelegatingStream.Read(Byte[], Int32, Int32)
2d67e854 6fe7547d System.Xml.XmlTextReaderImpl.InitStreamInput(System.Uri, System.String, System.IO.Stream, Byte[], Int32, System.Text.Encoding)
2d67e884 6fe73034 System.Xml.XmlTextReaderImpl.FinishInitStream()
2d67e894 6fe72fed System.Xml.XmlTextReaderImpl..ctor(System.IO.Stream, Byte[], Int32, System.Xml.XmlReaderSettings, System.Uri, System.String, System.Xml.XmlParserContext, Boolean)
2d67e8c4 6fe6f8c7 System.Xml.XmlReaderSettings.CreateReader(System.IO.Stream, System.Uri, System.String, System.Xml.XmlParserContext)
2d67e8e4 6fe6ebf6 System.Xml.XmlReader.Create(System.IO.Stream, System.Xml.XmlReaderSettings, System.String)
2d67e8f8 10909284 Microsoft.WindowsAzure.Storage.StorageExtendedErrorInformation.ReadFromStream(System.IO.Stream)
2d67e924 10908cb6 Microsoft.WindowsAzure.Storage.Core.Util.Exceptions+d__0.MoveNext()
2d67e984 1090882c System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.__Canon, System.Private.CoreLib]].Start[[Microsoft.WindowsAzure.Storage.Core.Util.Exceptions+d__0, Microsoft.WindowsAzure.Storage]](d__0 ByRef)
2d67e9b8 109087c0 Microsoft.WindowsAzure.Storage.Core.Util.Exceptions.PopulateStorageExceptionFromHttpResponseMessage(System.Net.Http.HttpResponseMessage, Microsoft.WindowsAzure.Storage.RequestResult, System.Func`4)
2d67ea04 10900dcb Microsoft.WindowsAzure.Storage.Core.Executor.Executor+d__4`1[[System.__Canon, System.Private.CoreLib]].MoveNext()
2d67ecec 723143d1 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext(System.Object)
2d67ecf4 722770eb System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
2d67ed28 7231442b System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunnerWithContext.RunWithCapturedContext()
2d67ed4c 722ec367 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
2d67ed78 722bac20 System.Threading.Tasks.Task.FinishContinuations()
2d67ede8 722b972f System.Threading.Tasks.Task.FinishStageThree()
2d67edf4 722ef715 System.Threading.Tasks.Task`1[[System.__Canon, System.Private.CoreLib]].TrySetResult(System.__Canon)
2d67ee04 723c9505 System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.__Canon, System.Private.CoreLib]].SetResult(System.__Canon)
2d67ee20 6fc97be4 System.Net.Http.HttpClient+d__58.MoveNext()
2d67ee74 723143d1 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext(System.Object)
2d67ee7c 722770eb System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
2d67eeb0 7231442b System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunnerWithContext.RunWithCapturedContext()
2d67eed4 722ec367 System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(System.Action, Boolean, System.Threading.Tasks.Task ByRef)
2d67ef00 722bac20 System.Threading.Tasks.Task.FinishContinuations()
2d67ef70 722b972f System.Threading.Tasks.Task.FinishStageThree()
2d67ef7c 722ef715 System.Threading.Tasks.Task`1[[System.__Canon, System.Private.CoreLib]].TrySetResult(System.__Canon)
2d67ef8c 72403fcd System.Threading.Tasks.TaskCompletionSource`1[[System.__Canon, System.Private.CoreLib]].TrySetResult(System.__Canon)
2d67ef9c 6fc9a7b8 System.Net.Http.WinHttpHandler+d__105.MoveNext()
2d67f050 723143d1 System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext(System.Object)
2d67f058 722770eb System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
2d67f08c 7231442b System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunnerWithContext.RunWithCapturedContext()
2d67f0b0 722ec1ac System.Threading.Tasks.AwaitTaskContinuation.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
2d67f0bc 7231265d System.Threading.ThreadPoolWorkQueue.Dispatch()
2d67f10c 72404b5a System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
2d67f31c 72bf309f [DebuggerU2MCatchHandlerFrame: 2d67f31c] 

From what I can tell, the cause seems to be that StorageExtendedErrorInfomration.ReadFromStream() calls XmlReader which is not asynchronous. XmlReader calls https://github.com/dotnet/corefx/blob/master/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpResponseStream.cs#L248 which wraps an asynchronous call in a Task and blocks via GetResult(). This seems to be the root cause of our deadlock.

I assume we are just getting transient error spikes from Azure blob storage, which is causing all these logging requests to error at the same time. This causes the thread pool to go over the 682 limit (verified via !ThreadPool in windbg) and the whole process completely deadlocks in a way that can’t be easily auto-mitigated or healed against.

On our end the only thing I can do from here is to rip out azure storage and go to some other mechanism.

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
erezvani1529commented, Mar 13, 2017

Hi @KallDrexx,

As you have correctly identified the synchronous read call from XmlReader triggers the sync over async call causing the thread exhaustion issue. We have been internally following up with CoreFx networking team since we discovered this pattern and will post upon any updates we receive.

However, we will have a fix/workaround on our end in the error parsing path until we make the refactoring change we need, to fully support async reads from response. We are planning to include this change in our upcoming release 8.2 as a bug fix.

This issue will be used to track the change.

Thanks, Elham

0reactions
erezvani1529commented, Nov 13, 2017

This issue has been in v8.2+. Please let us know if you see any further issues.

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is deadlock or application hung state possible for ASP.NET ...
In this scenario, the app will deadlock with the 2nd entrance of the method. ... And here's how to execute the Worker to...
Read more >
Debugging deadlock - .NET Core
In this tutorial, you'll learn how to debug a deadlock scenario. Using the provided example ASP.NET Core web app source code repository, you...
Read more >
Avoiding And Detecting Deadlocks In .NET Apps with C# ...
Note that for non-reentrant locks, a single thread can cause a deadlock with itself. Most locks are reentrant, eliminating this possibility.
Read more >
Deadlocks in your .NET app - YouTube
How to spot and avoid deadlocks in asp. net core c# applications. Patreon https://www.patreon.com/raw_coding Courses ...
Read more >
Understanding Async, Avoiding Deadlocks in C# | by Eke ...
Any blocking code will block the thread pool and any .Result will lead to a deadlock. If you're writing a ASP.NET web application,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found