Windows Azure Storage 之 Retry Policy (用來處理短暫性錯誤-Transient Fault)

在使用Windows Azure Storage Service 的時候, 一般會遇到各類各樣的問題。網絡

例如網絡鏈接不穩定,致使請求沒有發出去。刪除一個Blob Container 以後又馬上建立同名的Container。spa

這些狀況都有可能使得你的代碼拋出異常。這種異常咱們一般叫他:Transient Fault 翻譯成中文就是短暫性異常。翻譯

處理這種異常最簡單有效的途徑就是過幾秒鐘以後再從新發送請求。rest

Retry Policy就是用來幫助咱們完成這樣一項工做的。code

Retry Policy中自帶三個已經封裝好了能夠直接使用的類,分別有着不一樣的重試策略。orm

1.LinearRetryblog

這個類提供一個平行線式的重試策略接口

clip_image002

上圖展現了LinearRetry的重試策略。它一共重試了五次,每一次的時間間隔都是5秒,第六次因爲已經超過了預設定的重試次數,因此就放棄了。ip

使用LinearRetry的方法以下。string

static string accountName = "<storage account name>";
static string accountKey = "<storage account key>";
static void Main(string[] args)
{
    var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
    string blobContainerName = "temp-" + DateTime.UtcNow.Ticks;
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    IRetryPolicy exponentialRetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(2), 10);
    blobClient.RetryPolicy = exponentialRetryPolicy;
    CloudBlobContainer blobContainer = blobClient.GetContainerReference(blobContainerName);
    blobContainer.Create();
    Console.WriteLine("Blob container created.");
    Console.ReadLine();
}

 

2.ExponentialRetry

這個類提供了一個遞增式的重試策略

很明顯這是一個指數級別的重試策略,每一次重試的時間間隔都是以前的2倍。

使用ExponentialRetry方法以下:

static string accountName = "<storage account name>";
static string accountKey = "<storage account key>";
static void Main(string[] args)
{
    var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
    string blobContainerName = "temp-" + DateTime.UtcNow.Ticks;
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    IRetryPolicy linearRetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 10);
    blobClient.RetryPolicy = linearRetryPolicy;
    CloudBlobContainer blobContainer = blobClient.GetContainerReference(blobContainerName);
    IRetryPolicy noRetryPolicy = new NoRetry();
    BlobRequestOptions requestOptions = new BlobRequestOptions()
    {
        RetryPolicy = noRetryPolicy,
    };
    blobContainer.Create(requestOptions);
    Console.WriteLine("Blob container created.");
    Console.ReadLine();
}

 

 

3.NoRetry

這個類的重試策略就是不重試,這個策略看似矛盾,其實它是用來配合以前兩種策略來使用的,當你但願一個Blob Container的全部操做都能應用重試策略,惟獨Create Blob不使用重試策略的時候你就須要用到NoRetry了。 代碼以下:

static string accountName = "<storage account name>";
static string accountKey = "<storage account key>";
static void Main(string[] args)
{
    var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
    string blobContainerName = "temp-" + DateTime.UtcNow.Ticks;
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    IRetryPolicy linearRetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 10);
    blobClient.RetryPolicy = linearRetryPolicy;
    CloudBlobContainer blobContainer = blobClient.GetContainerReference(blobContainerName);
    IRetryPolicy noRetryPolicy = new NoRetry();
    BlobRequestOptions requestOptions = new BlobRequestOptions()
    {
        RetryPolicy = noRetryPolicy,
    };
    blobContainer.Create(requestOptions);
    Console.WriteLine("Blob container created.");
    Console.ReadLine();
}

 

除了以上三個已經封裝好的類之外,咱們還能夠本身建立自定義的重試策略類, 咱們只須要實現IRetryPolicy接口便可。

實現自定義類的一個好處是能夠自定義控制在何種特定狀況下才進行重試。

下面代碼將自定義一個實現了IRetryPolicy接口的 自定義類。

 

public class ContainerBeingDeletedRetryPolicy : IRetryPolicy
{
    int maxRetryAttemps = 10;
 
    TimeSpan defaultRetryInterval = TimeSpan.FromSeconds(5);
 
    public ContainerBeingDeletedRetryPolicy(TimeSpan deltaBackoff, int retryAttempts)
    {
        maxRetryAttemps = retryAttempts;
        defaultRetryInterval = deltaBackoff;
    }
 
    public IRetryPolicy CreateInstance()
    {
        return new ContainerBeingDeletedRetryPolicy(TimeSpan.FromSeconds(2), 5);
    }
 
    public bool ShouldRetry(int currentRetryCount, int statusCode, Exception lastException, out TimeSpan retryInterval, OperationContext operationContext)
    {
        retryInterval = defaultRetryInterval;
        if (currentRetryCount >= maxRetryAttemps)
        {
            return false;
        }
        //Since we're only interested in 409 status code, let's not retry any other operation.
        if ((HttpStatusCode)statusCode != HttpStatusCode.Conflict)
        {
            return false;
        }
        //We're only interested in storage exceptions so if there's any other exception, let's not retry it.
        if (lastException.GetType() != typeof(StorageException))
        {
            return false;
        }
        else
        {
            var storageException = (StorageException)lastException;
            string errorCode = storageException.RequestInformation.ExtendedErrorInformation.ErrorCode;
            if (errorCode.Equals("ContainerBeingDeleted"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        return true;
    }
}

 使用代碼以下:

static string accountName = "<storage account name>";
static string accountKey = "<storage account key>";
static void Main(string[] args)
{
    var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, accountKey), true);
    string blobContainerName = "temp-" + DateTime.UtcNow.Ticks;
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    IRetryPolicy linearRetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 10);
    blobClient.RetryPolicy = linearRetryPolicy;
    CloudBlobContainer blobContainer = blobClient.GetContainerReference(blobContainerName);
    blobContainer.Create();
    Console.WriteLine("Blob container created.");
    blobContainer.Delete();
    Console.WriteLine("Blob container deleted.");
    IRetryPolicy containerBeingDeletedRetryPolicy = new ContainerBeingDeletedRetryPolicy(TimeSpan.FromSeconds(2), 10);
    BlobRequestOptions requestOptions = new BlobRequestOptions()
    {
        RetryPolicy = containerBeingDeletedRetryPolicy,
    };
    blobContainer.Create(requestOptions);
    Console.WriteLine("Blob container created.");
    Console.ReadLine();
}

這個類只用於處理返回409錯誤而且錯誤信息 "Blob container created." 的錯誤,其餘錯誤則忽略掉了。

總結:

像上面這種,在一個方法中刪除一個container而且重建同名container的狀況很容易就產生 Transient Fault。

這時使用RetryPolicy就可以很好的解決這種異常了!

相關文章
相關標籤/搜索