29

所以场景是我使用 SB 队列来限制对其他服务的传出回调。回调其他服务的标准问题之一是它们可能会在无法控制的时间内停机。假设我检测到目标已关闭/未响应,那么放弃该消息以使其不会立即重新出现在队列中的最佳模式是什么?

以下是我知道、尝试过或正在考虑的一些方法:

  • 显然,如果我只是使用BrokeredMessage::Abandon()该消息将被解锁并放回队列中。对于这种情况以及我试图避免的情况,这显然是不可取的。

  • 如果我只是忽略了我遇到错误并且从不调用 Abandon 的事实,这将阻止它立即出现,但我并没有真正细粒度地控制它再次出现之前的时间,我想实现一个衰减重试策略。

  • 我想也许我可以调用BrokeredMessage::Abandon(IDictionary<string, object>)并以某种方式更新ScheduledEnqueueTimeUTC属性,但我已经尝试过了,除了最初发送消息之外,似乎没有办法影响该属性。有道理,但认为值得一试。

  • 我考虑过仅BrokeredMessage::Complete()在这种情况下使用,实际上只是将带有属性集的消息的新副本排入队列。ScheduledEqueueTimeUTC

最后的子弹似乎太重了,但我得出的结论是,鉴于队列的固有性质,这可能是正确的答案。我只是想在我缺少的 Azure SB 队列中可能有更好的方法来执行此操作。

4

5 回答 5

6

如果你想把消息放一段时间,并且你有一个地方写下 SequenceNumber(它可能在会话队列中处于会话状态),你可以 Defer() 它。可以使用一个特殊的 Receive 重载来检索延迟消息,该重载给出了 SequenceNumber;除了过期之外,这也是再次获得它们的唯一方法,所以要小心。此功能是为工作流和状态机构建的,以便它们可以处理乱序消息到达。

于 2013-04-30T16:09:38.753 回答
1

在上面的第 2 条中:您不能在调用时在消息上设置 TTL 时间跨度Receive(TimeSpan)而不是默认值Receive()吗?然后,您可以简单地放弃消息(无需调用Abandon()),当 TTL 过期时,消息应该会重新出现在队列中。虽然这并不能让您细粒度地控制说“x 秒后重新出现”,但它确实让您可以预测消息何时重新出现。

注意:使用基于存储的队列,您可以更新不可见超时,以便您可以对消息重新出现进行细粒度控制。

于 2013-04-30T01:29:25.667 回答
1

感觉有点hacky,但我想出的解决方案是

try 
{
   ...
}
catch (Exception ex)
{
   await Task.Delay(30000);
   throw;
}

这样,它将等待 30 秒,然后才允许它放弃。在配置的次数之后,它最终会死信。

我正在使用 Azure Webjobs 进行接收。虽然我使用它Task.Delay而不是Thread.Sleep它似乎并没有释放线程以在等待时处理队列中的另一个项目(默认情况下,Webjobs 并行处理 16 个)。

于 2016-07-29T15:41:02.843 回答
0

如果我是你,我会咨询 Internet 上的众多企业集成模式页面之一以寻求解决方案。基本上,您想要重试,如​​果它失败,则将消息连续发送到死信队列。然后我们可以在以后重新排队这些消息。根据要求,这可以是手动的或自动的。

请注意,虽然我发送给您的页面与骆驼相关,因此该页面上描述的所有内容都适用于 .NET 和 azure。如果您有兴趣,这里有一个更 .NET 的http://www.eaipatterns.com/

于 2013-04-29T23:14:25.347 回答
0

我更喜欢最后一种方法,因为它似乎是使用 Azure 服务总线的内置功能的最简单的解决方案。

流程是这样的:

var newMessage = new BrokeredMessage();
// Copy message body and properties from original message...

var scheduleTimeUtc = DateTimeOffset.UtcNow.Add(...);
await queueClient.ScheduleMessageAsync(newMessage, scheduleTimeUtc);

await originalMessage.CompleteAsync()
于 2017-09-07T13:02:15.860 回答