我有一个Azure WebJob函数,用于侦听Azure ServiceBus队列上的消息。通常当我在我的代码中遇到异常时,根据Azure WebJobs SDK documentation放弃该消息:
SDK以PeekLock模式接收消息,如果函数成功完成,则在消息上调用Complete;如果函数失败,则调用Abandon。如果该函数的运行时间超过PeekLock超时,则会自动更新锁定。
根据Azure ServiceBus documentation,这应该意味着消息再次可用,并将重试:
如果应用程序由于某种原因无法处理消息,则可以对收到的消息(而不是CompleteAsync)调用AbandonAsync方法。此方法使服务总线能够解锁消息并使其可由同一消费者或其他竞争消费者再次接收。其次,存在与锁相关联的超时,并且如果应用程序在锁定超时到期之前未能处理该消息(例如,如果应用程序崩溃),则服务总线解锁该消息并使其可用于再次接收(实质上默认情况下执行AbandonAsync操作)。
上面描述的行为通常会发生,但我发现此规则有例外。如果我的代码专门抛出TaskCanceledException
,则消息不会被放弃,因为它应该:
public void ProcessQueueMessage([ServiceBusTrigger("queue")] BrokeredMessage message, TextWriter log)
{
throw new TaskCanceledException();
}
通过Web作业运行此功能时,我看到错误消息打印出来当天,但消息没有任何重试而没有进入死信队列。如果我用TaskCanceledException
替换上面的InvalidOperationException
,那么消息就会被删除并按原样重试(我已经针对实际的ServiceBus队列验证了这一点)。
我无法找到任何有关此行为的解释。目前我正在将TaskCanceledException
包装在另一个例外中以解决该问题。
我在Azure WebJobs SDK中遇到错误了吗? TaskCanceledException
在这方面是否特别,还是做其他类型的例外有类似的行为?
我使用以下NuGet包:
如果执行不成功,函数应该放弃消息。如果你说消息没有被放弃并重试,即使它应该是(假设MaxDeliveryCount
被设置为大于1并且接收模式是PeekLock
),那么它可能是函数而不是Azure Service Bus的问题。您可以通过运行控制台应用程序并执行相同操作来验证,检查消息完成的任何位置,并从队列中删除或仍然在队列中并可供使用。
此外,看起来您正在使用旧版本的WebJobs(和Azure Service Bus)。执行验证时,您需要使用较旧的Azure Service Bus客户端(WindowsAzure.ServiceBus)而不是新的客户端(Microsoft.Azure.ServiceBus)。