429的Azure存储响应代码

时间:2017-06-16 17:50:29

标签: azure azure-storage azure-table-storage

我们的服务位于GatewayServer之后。如果下游依赖项返回适当的响应代码并且根据网关服务器上设置的超时时间,网关服务器会自行重试。

通过Azure存储文档,从该页面可以看出,存储客户端似乎没有返回429响应:

https://docs.microsoft.com/en-us/rest/api/storageservices/table-service-error-codes

https://docs.microsoft.com/en-us/azure/storage/storage-performance-checklist

从以上链接的重试部分: 在某些情况下,存储服务可能会限制您的应用程序,或者由于某些瞬态情况而无法提供请求,并返回“503 Server busy”消息或“500 Timeout”。客户端库知道哪些错误是可重试的,哪些不是。

由于Storage Client库未返回429,我们无法决定是否应尝试重试?重要的是如何确定给定的5xx错误是否可以在我们的端重试,这样我们就不会重试并将429返回给重试所有这些请求的网关服务器?我们的想法是,我们希望避免在不同层上重试,让Gateway Server根据下游服务的响应和超时集做出决定。

是否有标题或特定错误消息我们可以转而做出此决定?

1 个答案:

答案 0 :(得分:0)

好问题!这里要理解的关键是存储服务本身永远不会重试失败的操作。对于每个操作,服务将只返回HTTP状态代码。 Onus位于客户端以推断这些状态代码并在需要时执行重试。

如果我们以.Net存储客户端库为例,那里有一个内置的重试机制,它拦截错误代码并执行重试。如果我没有弄错,默认的重试机制是Exponential Retry

但是,您可以编写自己的重试逻辑并将其注入代码中。每当发生错误时,您的重试逻辑就会到位并且将重试请求。

前段时间我写了一篇关于这个话题的博客文章,你可能觉得有用:http://gauravmantri.com/2012/12/30/storage-client-library-2-0-implementing-retry-policies/。我确实意识到这是一个相当古老的帖子,而且已经发生了很多变化,但是这应该会让你对如何实现自己的重试策略有所了解。

在这篇博客文章中,我写了一些示例代码,当您删除容器并立即使用相同名称创建新容器时,该代码将重试。由于删除容器可能需要一些时间,因此在正常情况下,您将从服务返回409错误代码,默认情况下不可重试。但是使用此自定义重试策略,您的代码将重试为" x"创建blob容器。放弃之前的次数。

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();
}