我尝试以异步方式将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的 结果)`。
答案 0 :(得分:6)
Azure中的队列设计的吞吐量为每秒2000条消息。
请参阅:Azure Storage Scalability and Performance Targets
当您的应用程序达到分区可以处理的工作负载的限制时,Azure存储将开始返回错误代码503(服务器忙)或错误代码500(操作超时< / strong>)回复。发生这种情况时,应用程序应使用指数退避策略进行重试。指数退避允许分区上的负载减少,并减轻流向该分区的流量峰值。
答案 1 :(得分:1)
您似乎可以通过将QueryRequestOptions
传递给AddMessageAsync
来建立更强大的机制。
在发送查询之前,请求消息会将这些属性添加到命令中。
我会尝试传递QueryRequestOptions
并将值设置为MaximumExecutionTime
和ServerTimeout
并使用更大的值。
这是请求在发送之前填写的方式:
// 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;
};