【问题标题】:MSMQ + WCF - Immediately Move Messages to the Dead-Letter QueueMSMQ + WCF - 立即将消息移动到死信队列
【发布时间】:2014-07-20 15:15:07
【问题描述】:

我们有一个 WCF 服务,用于侦听队列 (MSMQ) 上的消息。它向我们的 Web 服务器 (REST API) 发送一个请求,该请求返回一个 HTTP 状态代码。

如果状态码在 400 范围内,我们将丢弃该消息。这个想法是 400 范围错误永远不会成功(未经授权、错误请求、未找到等),因此我们不想继续重试。

对于所有其他错误(例如,500 - 内部服务器错误),我们将 WCF 配置为将消息放入“重试”队列。重试队列上的消息会在一定时间后重试。思路是服务器暂时宕机了,等一下再试。

WCF的设置方式,如果我们在服务契约中抛出一个FaultException,它会自动将消息放到重试队列中。

当消息导致 400 范围错误时,我们只是在吞噬错误(我们只是记录它)。这可以防止重试机制触发;但是,最好将消息移动到死信队列。这样我们就可以通过向用户和/或系统管理员发送电子邮件来对错误做出反应。

有没有办法立即将这些坏消息移到死信队列?

【问题讨论】:

  • 我知道您想使用 WCF,但是如果您只使用 MessageQueue 类,您的要求就可以轻松完成。 MSMQ 中有很多内容是 WCF 阻止您使用的。 msdn.microsoft.com/en-us/library/…

标签: wcf message-queue msmq netmsmqbinding wcf-4


【解决方案1】:

希望我已经理解您的问题,如果这是我认为您所说的,那么是的,但是您显然需要对其进行编程才能做到这一点。但是您确实需要设置重试量,以便 MSMQ 可以重试直到放弃。或者您可以为死信/消息创建自己的自定义队列

http://msdn.microsoft.com/en-us/library/ms789035(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/ms752268(v=vs.110).aspx

也请看这里:

http://www.michaelfcollins3.me/blog/2012/09/20/wcf-msmq-bad-message-handling.html

How do I handle message failure in MSMQ bindings for WCF

我希望这些链接有所帮助。

【讨论】:

  • 因此,通常情况下,一条消息仅根据MaxRetryCycles 属性重试指定次数。但就我而言,重试没有意义。我想立即进入死信队列。
  • 我想知道是否必须手动创建死信队列的另一个端点,创建另一个服务合同并创建另一个客户端并在 400 处理代码中显式调用它。直接进入死信队列似乎很多。
  • 是的,我认为您不能直接进入死信队列。也许您应该将最大重试周期设置为 1 - 重试有什么害处?它第一次失败,所以它可能第二次失败,或者它可能成功(这很好)
  • @Ahmedilyas 如果您将最大重试次数设置为 1,这将影响 所有消息,即使是可能失败一次但有机会下次成功的消息。重试 1 不仅阻止了 400 次请求,而且严重限制了 MSMQ 的使用充分性
  • @MickyDuncan - 谢谢。我的印象是,如果消息未能传递,重试将重试消息 - 简单。
【解决方案2】:

首先,我一直提到死信队列。在我发布这个问题时,我不知道 WCF/MSMQ 会自动创建所谓的毒子队列。任何无法在配置的次数内传递的消息都被放入毒子队列中。

在我的情况下,我知道有些消息永远不会成功,所以我想立即将消息移出队列。

解决方案是创建第二个队列,我称之为“毒药”(不要与毒药子队列混淆)。我的 catch 块将创建一个 WCF 客户端实例并将消息转发到此毒物队列。我可以重用同一个客户端来发布到原始队列和毒队列;我只需要在每个配置文件中创建一个单独的客户端端点。

我运行了两个单独的 ServiceHost 实例来读取队列。当发生不可恢复的错误时,原始队列的ServiceHost 执行 HTTP 请求并将消息转发到毒队列。第二个ServiceHost 会简单地发送一封电子邮件以记录消息丢失。

还有超过最大尝试次数的临时错误问题。 WCF/MSMQ 自动创建一个名为<myqueuename>;poison 的子队列。您不能通过 WCF 直接写入子队列,但可以使用 ServiceHost 从中读取。每当消息最终进入毒子队列时,我只需将消息转发到毒子队列,使用与原始处理程序的 catch 块中使用的完全相同的客户端。

我希望能够在错误电子邮件中包含堆栈跟踪。由于我为所有处理程序重用相同的客户端和服务合同,我不能只将堆栈跟踪作为字符串传递(除非我将它添加到我的所有数据合同中)。相反,我让毒物处理程序再次尝试执行代码,这将再次失败并吐出堆栈跟踪。

这就是我的消息队列最终的样子:

MyQueue
    - Queue messages
    - Retry
    - Poison
MyQueuePoison
    - Queue messages

这种方法相当复杂。从 WCF 服务处理程序中调用 WCF 客户端很奇怪。这也意味着在服务器上再设置一个队列,以及大量用于指定客户端应将消息转发到哪个队列的额外配置部分。

【讨论】:

    猜你喜欢
    • 2011-06-02
    • 2012-12-28
    • 2012-09-23
    • 2023-04-07
    • 2011-07-31
    • 2013-10-14
    • 2012-02-19
    • 2020-07-12
    • 2019-02-02
    相关资源
    最近更新 更多