我不断地以查看模式接收消息,如果处理失败(不是传递)则放弃它们。但是,该消息立即再次可用并被再次接收以进行处理。它再次很快失败,并且在最大交付量之后它就变成了死信。
有没有办法配置主题/订阅在放弃消息后等待再发布消息?最好以指数方式。
当然,我也欢迎通过代码提出建议。
无法在服务总线配置中设置指数退避。我也遇到过同样的问题,并做了以下操作:
我们已将服务总线消息队列有效负载包装在一个指定传递尝试次数的类中。我们将投递尝试次数乘以一个常数,然后将该数字添加到当前日期时间以供将来计划投递。在超出我们想要尝试的传递尝试次数后,我们明确地对消息进行死信。
编辑 2020 年 7 月 17 日 考虑使用 Azure 持久任务框架,它内置了可自定义的重试策略。
另一种选择是使用 MassTransit,它支持 Azure 服务总线。
看看其广泛的重试配置。
请注意,收到消息后,MassTransit 会在内存中有效地进行重试,因此您需要适当调整主题订阅的
MaxDeliveryCount
和 MaxAutoRenewDuration
设置。
您的配置可能类似于:
var busControl = Bus.Factory.CreateUsingAzureServiceBus(cfg =>
{
var host = cfg.Host(serviceBusConnectionString, hst => { });
cfg.UseMessageRetry(retryConfigurator =>
RetryConfigurationExtensions.Exponential(retryConfigurator, ...);
cfg.SubscriptionEndpoint(
"subscriptionName",
"topicPath",
e =>
{
e.Consumer<SomeConsumer>();
// Let MassTransit do the retries
e.MaxDeliveryCount = 1;
e.MaxAutoRenewDuration = TimeSpan.FromMinutes(10);
});
});
您可以使用预定消息来实现此目的。
本质上,当您需要重试消息时,您只需在将来安排它,一旦经过足够的时间,服务总线就会再次将其添加到队列中:
ServiceBusSender queue = ...
int secs = // calculate the delay
var msg = new ServiceBusMessage("My scheduled message body")
{
ApplicationProperties =
{
["RetryCount"] = retryCount,
},
};
logger.LogInformation("Scheduling for " + secs + " secs");
await queue.ScheduleMessageAsync(msg, DateTimeOffset.Now.AddSeconds(secs));
您必须在标头或正文中添加有关重试计数的信息。否则你不知道自己尝试了多少次,也无法真正计算出未来的日期。
消息在消息锁定期间应保持不可用/隐藏状态。如果您显式放弃消息(使用AbandonAsync方法),则锁定将被取消,使消息可供使用;如果您在没有明确放弃消息的情况下完成进程,Azure 将等到锁定持续时间结束后才使消息再次可用,这可能会给您带来更多的延迟。您可以调整它来实现您的重试操作;您还可以实现更完整的方法(例如指数退避),如here
所述我也在研究这个主题,并且遇到了来自 Microsoft 的 RetryExponential 类。
重试指数类
命名空间:Microsoft.ServiceBus
程序集:Microsoft.ServiceBus.dll代表重试策略的实现。每次必须重试消息传递操作时,重试之间的延迟会以交错、指数方式增长。
public sealed class RetryExponential : Microsoft.ServiceBus.RetryPolicy