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

Mar*_*man 6 messaging wcf msmq message-queue

我有多个现有的应用程序,通过System.Messaging API使用MSMQ发送和接收消息.队列通常是非事务性的,是MSMQ 3和4的混合体.

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

我想利用MSMQ开箱即用的任何东西,以及围绕此问题的任何流行或最佳实践模式,而不是重新发明轮子.为此,有很多关于MSMQ 4中对有害消息的额外支持.但它们似乎不容易通过.Net访问.此外,我可以找到使用它们的唯一引用是通过带有MSMQ绑定的WCF.

如果没有使用WCF,任何人都可以建议任何模式或指向实现重试的任何示例吗?

Mar*_*man 7

我无法找到一个单一,流行的模式来做到这一点.但是在对System.Messaging进行了一些讨论之后,我能够利用Message属性和MSMQ行为来实现我认为用最少的移动部件完成工作的合适方式.

这是我实施的内容.事实证明它相当简单和轻量级 - 代码不多且易于维护:

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

int Order,int NumberOfRetries,TimeSpan Delay

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

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

int Attempts,string SourceQueuePath

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

最后,我在接收器的配置中添加了一个等待队列路径.此队列是消息在"超时"时丢弃的位置.

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

接收器然后将Message的TimeToBeRecieved(TTBR)属性设置为DateTime.Now加上相应RetryLevel的Delay值.然后,它将AdministrativeQueue属性设置为从RetryInfo的SourceQueuePath属性创建的Queue,并将Message的AcknowledgeType设置为AcknowledgeTypes.NegativeReceive.最后,它将Message放在等待队列中.

从这里开始,MSMQ会观看Message的TTBR.当它超时时,MSMQ将消息放回其AdministrativeQueue属性中的队列,该属性是消息最初来自的队列.如果处理程序继续拒绝该消息,它只会向上移动RetryLevels.

如果消息的尝试超出了配置的RetryLevels上的所有NumberOfRetries,则消息的TTBR属性设置为TimeSpan.Zero,UseDeadLetterQueue属性设置为true,并且消息将像其他任何重试一样放在等待队列中.但是,这一次,它立即超时,MSMQ将其发送到等待队列的主机的系统死信队列(DLQ),在那里可以手动处理.