异步发布到Azure队列

时间:2015-02-19 14:04:53

标签: c# async-await azure-queues

我尝试以异步方式将Azure队列中的邮件排入队列:

private async Task EnqueueItemsAsync(IEnumerable<string> messages) {
            var tasks = messages.Select(msg => _queue.AddMessageAsync(new CloudQueueMessage(msg),
                null, null, null, null));

            await Task.WhenAll(tasks);
        }

如果我说得对,这说“开始将一个项目排在另一个项目之后而不等待它们发布,请为每个任务保留一个参考,然后等到所有项目都被发布”。

此代码在大多数情况下都能正常工作,但是对于大量项目(5000),它会开始入队,然后会引发超时异常(在排队~3500项之后)。

我通过等待每一个完成然后继续下一个

来解决它
private async Task EnqueueItemsAsync(IEnumerable<string> messages) {
            foreach (var message in messages) {
                await _queue.AddMessageAsync(new CloudQueueMessage(message), null, null, null, null);
            }
        }

任何人都可以解释为什么会这样吗?

例外:

  

System.AggregateException包含许多此类例外:   Microsoft.WindowsAzure.Storage.Core.Util.AsyncExtensions.<>c__DisplayClass4.<CreateCallbackVoid>b__3(IAsyncResult ar)请求信息RequestID:RequestDate:StatusMessage:&lt; ---   ---&GT; (内部异常#1)Microsoft.WindowsAzure.Storage.StorageException:客户端不能   在指定的超时内完成操作。 ---&GT;   System.TimeoutException:客户端无法完成操作   在指定的超时内。 ---内部异常堆栈跟踪结束---   Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync [T](IAsyncResult的   结果)`。

2 个答案:

答案 0 :(得分:6)

Azure中的队列设计的吞吐量为每秒2000条消息。

请参阅:Azure Storage Scalability and Performance Targets

  

当您的应用程序达到分区可以处理的工作负载的限制时,Azure存储将开始返回错误代码503(服务器忙)或错误代码500(操作超时< / strong>)回复。发生这种情况时,应用程序应使用指数退避策略进行重试。指数退避允许分区上的负载减少,并减轻流向该分区的流量峰值。

答案 1 :(得分:1)

您似乎可以通过将QueryRequestOptions传递给AddMessageAsync来建立更强大的机制。

在发送查询之前,请求消息会将这些属性添加到命令中。

我会尝试传递QueryRequestOptions并将值设置为MaximumExecutionTimeServerTimeout并使用更大的值。

这是请求在发送之前填写的方式:

// Microsoft.WindowsAzure.Storage.Queue.QueueRequestOptions
internal void ApplyToStorageCommand<T>(RESTCommand<T> cmd)
{
    if (this.LocationMode.HasValue)
    {
        cmd.LocationMode = this.LocationMode.Value;
    }
    if (this.ServerTimeout.HasValue)
    {
        cmd.ServerTimeoutInSeconds = new int?((int)this.ServerTimeout.Value.TotalSeconds);
    }
    if (this.OperationExpiryTime.HasValue)
    {
        cmd.OperationExpiryTime = this.OperationExpiryTime;
        return;
    }
    if (this.MaximumExecutionTime.HasValue)
    {
        cmd.OperationExpiryTime = new DateTime?(DateTime.Now + this.MaximumExecutionTime.Value);
    }
}

这就是它的发送方式:

rESTCommand.PreProcessResponse = delegate(RESTCommand<NullType> cmd, HttpWebResponse resp, Exception ex, OperationContext ctx)
{
    HttpResponseParsers.ProcessExpectedStatusCodeNoException<NullType>(HttpStatusCode.Created, resp, NullType.Value, cmd, ex);
    return NullType.Value;
};