Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure blob DownloadToStream takes too long

I am trying to download a file from Azure blob, but in 0.1% cases it just hangs at the blockBlob.DownloadToStream(...) for more than 10 mins. Is there a way I can timeout this function in 2 mins?

CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
using (var memoryStream = new System.IO.MemoryStream())
{
   blockBlob.DownloadToStream(memoryStream, null, new BlobRequestOptions()
   {
        ServerTimeout = TimeSpan.FromSeconds(120)
   });
   string content = Encoding.UTF8.GetString(memoryStream.ToArray());
}
like image 363
Groot Avatar asked Dec 10 '22 23:12

Groot


2 Answers

You can configure the timeout for the whole DownloadToStream operation. For example, you can set MaximumExecutionTime to 120 seconds (this is for whole DownloadToStream operation), ServerTimeout to 30 seconds (this is for each REST call), and specify a RetryPolicy (ExponentialRetry or LinearRetry, this is for each REST call) to enable retrying while a request times out or fails. By doing so, each individual Get Blob REST call will be limited to 30 seconds at server side (retry policy will take effect if encountering server timeout issue), and the whole DownloadToStream operation will be limited to 2 minutes at client side.

Please refer to the code sample below. Note: The BlobRequestOptions object only needs to be constructed once, then you can use it for all blob related operations below.

        var maxRetryCount = 3;
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
        var blobRequestOptions = new BlobRequestOptions
        {
            ServerTimeout = TimeSpan.FromSeconds(30),
            MaximumExecutionTime = TimeSpan.FromSeconds(120),
            RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(3), maxRetryCount),
        };

        using (var memoryStream = new MemoryStream())
        {
            blockBlob.DownloadToStream(memoryStream, null, blobRequestOptions);
        }
like image 174
Zhaoxing Lu Avatar answered Dec 26 '22 02:12

Zhaoxing Lu


Thanks! I also got the following piece of code to retry download the blob after a timeout.

 CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
 var cts = new CancellationTokenSource((int)TimeSpan.FromSeconds(30 * (retryCount + 1)).TotalMilliseconds);

 using (var memoryStream = new System.IO.MemoryStream())
 {
    Task task = blockBlob.DownloadToStreamAsync(memoryStream, cts.Token);
    await task.ConfigureAwait(false);

    if (!task.IsCanceled && !task.IsFaulted)
    {
        return Encoding.UTF8.GetString(memoryStream.ToArray());                            
    }
    else if (task.IsCanceled)
    {
        retryCount++;
        Console.WriteLine("Task cancelled happened for blob: {0}. Increasing timeout to: {1} sec", blobName, retryCount * 30);
    }
}
like image 32
Groot Avatar answered Dec 26 '22 02:12

Groot