在没有WCF的MSMQ中创建重试机制



我有多个通过系统使用MSMQ发送和接收消息的现有应用程序。消息传递API。队列通常是非事务性的,并且是msmq3和msmq4的混合。

接收应用程序现在处理有害消息,以至于在第一次出现任何异常时,消息被放在错误队列中进行人工干预。但事实证明,绝大多数人工干预都是简单地将消息移回主队列进行另一次尝试,然后重试成功。因此,为了使该过程自动化,我想向接收器添加一个重试特性,以便消息在给定次数内被移动回主队列,每次消息之间具有给定的延迟。

与其重新发明轮子,我想利用MSMQ提供的任何现成的东西,以及任何流行的或最佳实践模式。为此,在msmq4中有很多关于有毒消息的额外支持。但它们似乎不容易通过。net访问。此外,我能找到的使用它们的唯一参考是通过带有MSMQ绑定的WCF。

谁能建议任何模式或指出任何例子,实现重试,如果一个人不使用WCF?

我找不到一个流行的模式来做这件事。但在系统里摸索了一下之后。在消息传递方面,我能够以我认为合适的方式利用Message属性和MSMQ行为,以最少的移动部件完成工作。

这是我实现的。结果证明它相当简单和轻量级——没有太多代码并且易于维护:

我创建了一个名为RetryLevel的对象,它有三个属性:

int秩序,int NumberOfRetries,延迟时间间隔

接收器应用程序的配置现在有一个RetryLevel列表。因此,新功能基本上支持n级重试。

然后我创建了一个名为RetryInfo的对象。这个对象有两个属性:

int尝试,字符串SourceQueuePath

RetryInfo对象的实例被序列化并存储在每条最终被重试的消息的Extension属性中。这允许我跟踪消息本身的当前重试状态,从而消除了维护单独的重试元数据存储的需要,以及协调消息id、保持数据同步等所有开销。

最后,我在接收器的配置中添加了一个等待队列路径。当消息处于"超时"状态时,该队列将被丢弃。

所以现在,当消息处理程序拒绝消息时,接收器反序列化它的RetryInfo(如果有),并查看(以前的)尝试次数,以确定它已达到配置的retrylevel中的哪个。

接收方然后设置消息的接收时间(TTBR)属性为日期时间。现在加上适当的RetryLevel的Delay值。然后它将AdministrativeQueue属性设置为从RetryInfo的SourceQueuePath属性创建的Queue,并将Message的AcknowledgeType设置为acknowledge types . negativerreceive。最后,它将消息放到等待队列中。

从这里,MSMQ监视消息的TTBR。当超时时,MSMQ将消息放回到其AdministrativeQueue属性中的队列中,该属性是消息最初来自的队列。如果消息继续被处理程序拒绝,它就会向上移动RetryLevels。

如果消息的重试次数超过配置的retrylevel上的所有重试次数,则消息的TTBR属性设置为TimeSpan。为零时,UseDeadLetterQueue属性被设置为true,消息就像任何其他重试一样被放到等待队列中。然而,这一次,它立即超时,MSMQ将它发送到等待队列主机的系统死信队列(DLQ),在那里它可以手工处理。

你说你不想重新发明轮子,我建议使用一个可用的框架,如masstrtransit或其他。

就我个人而言,我对NServiceBus有很好的体验,它位于MSMQ之上。

它使得配置错误处理非常容易。您可以为应用程序定义实际的工作队列,还可以定义专用的错误队列。此外,您还可以配置应用程序将尝试多少次(对您的代码自动且完全透明),直到它将有害消息移动到您选择的队列中。

这允许您轻松地配置如下内容:"如果我不能在5次重试内正确处理此消息,则将其移动到我的错误队列中。"

这是一个开箱即用的功能

示例配置(来自官方文档),注意Publisher部分的app.config:

官方文档中的基本发布/订阅配置http://images.nservicebus.com/basic_pubsub.png

至于非wcf部分,NServiceBus对于任何。net应用程序都可以很好地工作。您可以选择简单地引用dll,或者您可以使用NServiceBus作为容器来作为本地服务托管您的应用程序,或者您可以将其永久注册为windows服务。最后,如果有一天您改变了主意,转而使用WCF,它也会得到支持。: -)

最新更新