Azure-sdk-for-net: [BUG] .Net Framework hanging on BlobClient.DownloadAsync

Created on 22 Apr 2020  路  28Comments  路  Source: Azure/azure-sdk-for-net

Describe the bug
I am trying to download large blobs in chunks. I have the same exact code in a .Net 4.7.2 Framework console app and an .Net Core 3.1 console app. The .Net Core app works fine, the .Net Framework app ends up hanging on one of the download calls and eventually throws an error after it is retried 6 times.

This looks similar to Issue # 10027. The comments there try to imply that it is a network or host issue, but perhaps my example will help you reproduce the issue.

In my test I am attempting to download a blob that is 880MB in size.

Expected behavior
The downloads should work correctly in .Net Framework

Actual behavior (include Exception or Stack Trace)
A few download calls complete successfully before getting this error (I only included 1 of the inner exceptions, there are 6 of them):

System.AggregateException: Retry failed after 6 tries. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpClientTransport.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()
--- End of inner exception stack trace ---
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.BlobRestClient.Blob.d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.Specialized.BlobBaseClient.d__45.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.Specialized.BlobBaseClient.d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.Specialized.BlobBaseClient.d__43.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at SafeguardControllerBusinessLogic.AzureStorageBusinessLogic.<DownloadImportBackupAsync>d__1.MoveNext() in C:\projects\Safeguard\SafeguardControllerBusinessLogic\AzureStorageBusinessLogic.cs:line 98 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()
at SafeguardControllerBusinessLogic.ControllerHelperFunctions.d__39.MoveNext() in C:\projects\Safeguard\SafeguardControllerBusinessLogic\SafeguardControllerBusinessLogicClassLibrary.cs:line 1762
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at SafeguardController.ViewModels.ImportGroupsSettingsViewModel.d__77.MoveNext() in C:\projects\Safeguard\SafeguardController\ViewModels\ImportGroupsSettingsViewModel.cs:line 547
---> (Inner Exception #0) System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpClientTransport.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()<---

---> (Inner Exception #1) System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpClientTransport.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()<---

To Reproduce
Here is my sample app, same exact code in the .Net Framework 4.7.2 app and .Net Core 3.1 app. I've added the Azure.Storage.Blobs NuGet package version 12.4.1 to both. The sasURL string is a SAS string to one of my Azure storage containers. I'm trying to download in chunks so that I can display progress to the user.

 static async Task Main(string[] args)
        {
            string sasUrl = @"<sas string here>";
            BlobContainerClient blobContainerClient = new BlobContainerClient(new Uri(sasUrl), null);
            //create a blob client          
            BlockBlobClient blockBlobClient = blobContainerClient.GetBlockBlobClient(@"Backups/SGDataMar022020.wtsbak");
            var properties = await blockBlobClient.GetPropertiesAsync();
            int chunkSize = 5 * 1024 * 1024;   //5MB in bytes
            long fileSize = properties.Value.ContentLength;
            long blobLengthRemaining = fileSize;  //bytes of file to download        
            string fileName = Path.Combine(@"C:\Users\bkoth\Documents", @"Backups/SGDataMar022020.wtsbak");
            long totalChunks = (fileSize - 1) / chunkSize + 1;
            long startPosition = 0;
            int chunkIndex = 1;
            Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }

            do
            {
                long blockSize = Math.Min(chunkSize, blobLengthRemaining);
                var response = await blockBlobClient.DownloadAsync(
                    range: new Azure.HttpRange(startPosition, blockSize)
                    );
                byte[] buffer = new byte[blockSize];
                await response.Value.Content.ReadAsync(buffer: buffer,
                    offset: 0,
                    count: buffer.Length
                    );
                using (FileStream fileStream = new FileStream(path: fileName, mode: FileMode.OpenOrCreate))
                {
                    fileStream.Position = startPosition;
                    await fileStream.WriteAsync(buffer: buffer,
                        offset: 0,
                        count: buffer.Length);
                }
                startPosition += blockSize;
                blobLengthRemaining -= blockSize;
                double percent = (((double)chunkIndex) / (double)totalChunks) * 100;
                Console.WriteLine(string.Format("Percent complete: {0}%", Convert.ToInt32(percent)));
                chunkIndex++;
            } while (blobLengthRemaining > 0);

        }

Environment:
Azure.Storage.Blobs 12.4.1
.NET Core SDK (reflecting any global.json):
Version: 3.1.100
Commit: cd82f021f4

Runtime Environment:
OS Name: Windows
OS Version: 10.0.17134
OS Platform: Windows
RID: win10-x64
Visual Studio 16.4.2

Azure.Core Client Service Attention Storage customer-reported

Most helpful comment

@bruckGT
I've been playing with your sample and was able to repro. I'd recommend to change the following line:

await response.Value.Content.ReadAsync(buffer: buffer,
                    offset: 0,
                    count: buffer.Length
                    );

to:

                using (Stream stream = response.Value.Content)
                {
                    await stream.ReadAsync(buffer: buffer,
                        offset: 0,
                        count: buffer.Length
                        );
                }

i.e. make sure to dispose Response Stream when you're done reading it. Otherwise it stays open and blocks the connection.

All 28 comments

Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage.

@kasobol-msft lets talk tomorrow about this and see if we need to load balance.

@BenKoth I wasn't able to reproduce given provided sample. Could you please run it on your side with a verbose logging (per this page), i.e. add this early in Main method:

            using AzureEventSourceListener listener = new AzureEventSourceListener((e, message) =>
            {
                // Only log messages from Azure-Core event source
                if (e.EventSource.Name == "Azure-Core")
                {
                    File.AppendAllText("C:\\log.txt", $"{DateTime.Now} {message}");
                }
            },
             level: EventLevel.Verbose);

This will generate C:\log.txt file. Please share it with us.

I was also able to reproduce this behavior using .NET framework 4.6.1 as well and I got a somewhat similar stack trace. Looks like there's some sort of error in Azure.Core

As confirmed this error does not occur in Net Core 2.1 or Core 3.1

System.AggregateException
  HResult=0x80131500
  Message=Retry failed after 6 tries.
  Source=Azure.Core
  StackTrace:
   at Azure.Core.Pipeline.RetryPolicy.<ProcessAsync>d__11.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.<ProcessAsync>d__1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.<ProcessAsync>d__1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Storage.Blobs.BlobRestClient.Blob.<DownloadAsync>d__0.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Storage.Blobs.Specialized.BlobBaseClient.<StartDownloadAsync>d__45.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Storage.Blobs.Specialized.BlobBaseClient.<DownloadInternal>d__44.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Azure.Storage.Blobs.Specialized.BlobBaseClient.<DownloadAsync>d__43.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at StorageTester.Program.<Main>d__0.MoveNext() in C:\Users\amnguye\source\repos\TestOR\TestOR\Program.cs:line 38
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at StorageTester.Program.<Main>(String[] args)

  This exception was originally thrown at this call stack:
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(System.Threading.Tasks.Task<System.Net.Http.HttpResponseMessage>, System.Net.Http.HttpRequestMessage, System.Threading.CancellationTokenSource, bool)
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    Azure.Core.Pipeline.HttpClientTransport.ProcessAsync(Azure.Core.HttpMessage)
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    ...
    [Call Stack Truncated]

Inner Exception 1:
TaskCanceledException: A task was canceled.

Will update the issue once more investigation is done.

When attempting to enable logging, the error does not occur and error does not occur as often when attempting to debug the storage blob package.

When debugging, it succeeds making 3-4 download calls, but eventually will stall and throw the exception. Fiddler trace shows that the requests were sent, but the method shows it still has not returned yet. Sometimes after a stall, the method will return but not always. Usually the next download call will throw the same exception.

image

During these stalls the Diagnostic window shows multiple threads being exited with exit code 0.

image

More investigation may need to be done in Azure.Core to why this is only occurring in .NET Framework 4.6.1/4.7.2

@pakrym @tg-msft Could we get a bit of help with why Azure.Core is causing this to happen in .NET Framework 4.6.1/4.7.2 ?

Here is my log file
log.txt

@pakrym I think this might be it. I've checked server logs, the requests in last retry never made it to the backend. ServicePointManager allows 2 connections by default, so if we were leaking them then they'd be quickly exhausted.

Hi @pakrym, we have experienced the same issue in our production service. (tag @bruckGT)

  • When will the this fix be released? In which version of the SDK?
  • Is there any workaround?

Thanks!

Hi @pakrym, we have experienced the same issue in our production service. (tag @bruckGT)

  • When will the this fix be released? In which version of the SDK?
  • Is there any workaround?

Thanks!

We're going to release it this week.

@kasobol-msft Thanks for the quick turn-around. Looking forward to try on the new version.

Fixed in 12.4.3

Hi @kasobol-msft I think you meant 12.4.2?

@kasobol-msft Got it thanks!

@kasobol-msft updated version of Azure.Core haven't shipped yet and Storage dependency wasn't updated so the fix won't be in Azure.Storage.Blobs/12.4.3

Fix is in two places: shared code you linked and more important part in sdk/core/Azure.Core/src/Pipeline/Internal/ReadTimeoutStream.cs that ships with Azure.Core

Gotcha. I'll leave it open until Azure.Core ships then.

@pakrym @kasobol-msft Do we know a timeline of when Azure.Core will ship?

@bruckGT End of this week.

Hi @kasobol-msft , @pakrym
We updated to the latest Azure.Storage.Blobs sdk (12.4.4). However we are still seeing the same issue as before (calls to storage hangs and throws exception after 6 tries). We were able to reproduced this issue locally as well. We slightly modified the above code example by @BenKoth to mimick what our app does. So we have concurrent calls to check if blob exists as well as downloads large blob files. Eventually after alot of exists calls succeeding the download call gets stuck and throws the exception. I can provide the sample code if needed. Also one interesting thing is that it doesn't reproduce when we have fiddler turned on.

Environment:
Azure.Storage.Blobs 12.4.4
.NET Core SDK (reflecting any global.json):
Version: 3.1.100

Exception:

[17:39:25.964180] Download percent complete: 3%
System.AggregateException: Retry failed after 6 tries. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpClientTransport.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()
--- End of inner exception stack trace ---
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.BlobRestClient.Blob.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.Specialized.BlobBaseClient.d__73.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Storage.Blobs.Specialized.BlobBaseClient.d__72.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable1.ConfiguredTaskAwaiter.GetResult()
at BlobTestFx.Program.d__4.MoveNext() in D:\Demo\blobTest\BlobTestFx\Program.cs:line 101
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
at BlobTestFx.Program.

d__2.MoveNext() in D:\Demo\blobTest\BlobTestFx\Program.cs:line 25
---> (Inner Exception #0) System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpClientTransport.d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.RequestActivityPolicy.d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.ResponseBodyPolicy.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.LoggingPolicy.d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Azure.Core.Pipeline.HttpPipelineSynchronousPolicy.d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at Azure.Core.Pipeline.RetryPolicy.d__11.MoveNext()<---

@bruckGT The code sample would be very helpful.

 static async Task Main(string[] args)
        {
            try
            {
                Console.WriteLine("Start!");
                await Task.WhenAll(CheckingExistance(), DownloadTestFromGithub()).ConfigureAwait(false);
                Console.WriteLine("finished");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            Console.WriteLine("Press ESC to finish");
            var keyInfo = Console.ReadKey(intercept: false);
            while (keyInfo.Key != ConsoleKey.Escape)
            {
                keyInfo = Console.ReadKey(intercept: false);
            }
        }

        public static async Task CheckingExistance()
        {
            const int times = 300;
            var connectionString = "";
            BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
            BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient("dump");
            BlockBlobClient blockBlobClient = blobContainerClient.GetBlockBlobClient(@"10.0.0.4.dump.zip");

            for (int i = 0; i < times; i++)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss.ffffff}] Checking exists: {i + 1}");
                //create a blob client          
                await blockBlobClient.ExistsAsync().ConfigureAwait(false);
            }
        }

        public static async Task DownloadTestFromGithub()
        {
            var connectionString = "";
            BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
            BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient("dump");
            //create a blob client          
            BlockBlobClient blockBlobClient = blobContainerClient.GetBlockBlobClient(@"10.0.0.4.dump.zip");
            var properties = await blockBlobClient.GetPropertiesAsync();
            int chunkSize = 5 * 1024 * 1024;   //5MB in bytes
            long fileSize = properties.Value.ContentLength;
            long blobLengthRemaining = fileSize;  //bytes of file to download        
            string fileName = Path.Combine(@"c:\temp\", @"10.0.0.4.dump.zip");
            long totalChunks = (fileSize - 1) / chunkSize + 1;
            long startPosition = 0;
            int chunkIndex = 1;
            Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            if (File.Exists(fileName))
            {
                File.Delete(fileName);
            }

            do
            {
                long blockSize = Math.Min(chunkSize, blobLengthRemaining);
                var response = await blockBlobClient.DownloadAsync(
                    range: new Azure.HttpRange(startPosition, blockSize)
                    );
                byte[] buffer = new byte[blockSize];
                await response.Value.Content.ReadAsync(buffer: buffer,
                    offset: 0,
                    count: buffer.Length
                    );
                using (FileStream fileStream = new FileStream(path: fileName, mode: FileMode.OpenOrCreate))
                {
                    fileStream.Position = startPosition;
                    await fileStream.WriteAsync(buffer: buffer,
                        offset: 0,
                        count: buffer.Length);
                }
                startPosition += blockSize;
                blobLengthRemaining -= blockSize;
                double percent = (((double)chunkIndex) / (double)totalChunks) * 100;
                Console.WriteLine(string.Format($"[{DateTime.Now:HH:mm:ss.ffffff}] Download percent complete: {Convert.ToInt32(percent)}%"));
                chunkIndex++;
            } while (blobLengthRemaining > 0);
        }

@kasobol-msft

@bruckGT
I've been playing with your sample and was able to repro. I'd recommend to change the following line:

await response.Value.Content.ReadAsync(buffer: buffer,
                    offset: 0,
                    count: buffer.Length
                    );

to:

                using (Stream stream = response.Value.Content)
                {
                    await stream.ReadAsync(buffer: buffer,
                        offset: 0,
                        count: buffer.Length
                        );
                }

i.e. make sure to dispose Response Stream when you're done reading it. Otherwise it stays open and blocks the connection.

@kasobol-msft that fixes the local repro, thanks. We are currently releasing that in our production environment, to see if it fixes it there also.

Was this page helpful?
0 / 5 - 0 ratings