Implement a retry policy with .NET

Any application that runs in the cloud or communicates with remote services and resources must be able to handle transient faults. It's common for these applications to experience faults due to a momentary loss of network connectivity, a request timeout when a service or resource is busy, or other factors. Developers should build applications to handle transient faults transparently to improve stability and resiliency.

This article shows you how to use the Azure Storage client library for .NET to set up a retry policy for an application that connects to Azure Blob Storage. Retry policies define how the application handles failed requests, and should always be tuned to match the business requirements of the application and the nature of the failure.

Configure retry options

Retry policies for Blob Storage are configured programmatically, offering control over how retry options are applied to various service requests and scenarios. For example, a web app issuing requests based on user interaction might implement a policy with fewer retries and shorter delays to increase responsiveness and notify the user when an error occurs. Alternatively, an app or component running batch requests in the background might increase the number of retries and use an exponential backoff strategy to allow the request time to complete successfully.

The following table lists the properties of the RetryOptions class, along with the type, a brief description, and the default value if you make no changes. You should be proactive in tuning the values of these properties to meet the needs of your app.

Property Type Description Default value
Delay TimeSpan The delay between retry attempts for a fixed approach or the delay on which to base calculations for a backoff-based approach. If the service provides a Retry-After response header, the next retry is delayed by the duration specified by the header value. 0.8 second
MaxDelay TimeSpan The maximum permissible delay between retry attempts when the service doesn't provide a Retry-After response header. If the service provides a Retry-After response header, the next retry is delayed by the duration specified by the header value. 1 minute
MaxRetries int The maximum number of retry attempts before giving up. 5
Mode RetryMode The approach to use for calculating retry delays. Exponential
NetworkTimeout TimeSpan The timeout applied to an individual network operation. 100 seconds

In this code example for Blob Storage, we configure the retry options in the Retry property of the BlobClientOptions class. Then, we create a client object for the blob service using the retry options.

// Provide the client configuration options for connecting to Azure Blob Storage
BlobClientOptions blobOptions = new BlobClientOptions()
{
    Retry = {
        Delay = TimeSpan.FromSeconds(2),
        MaxRetries = 5,
        Mode = RetryMode.Exponential,
        MaxDelay = TimeSpan.FromSeconds(10),
        NetworkTimeout = TimeSpan.FromSeconds(100)
    },
};

BlobServiceClient blobServiceClient = new BlobServiceClient(
    accountUri,
    new DefaultAzureCredential(),
    blobOptions);

In this example, each service request issued from the BlobServiceClient object uses the retry options as defined in the BlobClientOptions object. You can configure various retry strategies for service clients based on the needs of your app.

Use geo-redundancy to improve app resiliency

If your app requires high availability and greater resiliency against failures, you can leverage Azure Storage geo-redundancy options as part of your retry policy. Storage accounts configured for geo-redundant replication are synchronously replicated in the primary region, and asynchronously replicated to a secondary region that is hundreds of miles away.

Azure Storage offers two options for geo-redundant replication: Geo-redundant storage (GRS) and Geo-zone-redundant storage (GZRS). In addition to enabling geo-redundancy for your storage account, you also need to configure read access to the data in the secondary region. To learn how to change replication options for your storage account, see Change how a storage account is replicated.

In this example, we set the GeoRedundantSecondaryUri property in BlobClientOptions. If this property is set, the secondary URI is used for GET or HEAD requests during retries. If the status of the response from the secondary URI is a 404, then subsequent retries for the request don't use the secondary URI again, as this status code indicates that the resource may not have propagated there yet. Otherwise, subsequent retries alternate back and forth between primary and secondary URI.

Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Provide the client configuration options for connecting to Azure Blob Storage
BlobClientOptions blobOptionsGRS = new BlobClientOptions()
{
    Retry = {
        Delay = TimeSpan.FromSeconds(2),
        MaxRetries = 5,
        Mode = RetryMode.Exponential,
        MaxDelay = TimeSpan.FromSeconds(10),
        NetworkTimeout = TimeSpan.FromSeconds(100)
    },

    // Set the secondary storage URI
    GeoRedundantSecondaryUri = secondaryAccountUri
};

BlobServiceClient blobServiceClient = new BlobServiceClient(
    accountUri,
    new DefaultAzureCredential(),
    blobOptionsGRS);

Apps that make use of geo-redundancy need to keep in mind some specific design considerations. To learn more, see Use geo-redundancy to design highly available applications.

Next steps

Now that you understand how to implement a retry policy using the Azure Storage client library for .NET, see the following articles for more detailed architectural guidance:

  • For architectural guidance and general best practices for retry policies, see Transient fault handling.
  • For guidance on implementing a retry pattern for transient failures, see Retry pattern.