首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何处理WCF的MSMQ绑定中的消息故障

如何处理WCF的MSMQ绑定中的消息故障
EN

Stack Overflow用户
提问于 2008-09-17 11:15:21
回答 4查看 14.1K关注 0票数 17

我已经创建了一个WCF服务,并且正在使用netMsmqBinding绑定。

这是一个简单的服务,它将Dto传递给我的服务方法,并且不期望得到响应。消息被放在MSMQ中,一旦被拾取,就被插入到数据库中。

确保数据不会丢失的最佳方法是什么?

我已经尝试了以下两种方法:

  1. 引发异常

这会将消息放在死信队列中,以供手动细读。我可以在我的策略启动时处理此问题

  1. 在绑定上设置receiveRetryCount="3“

在3次尝试之后--这是瞬间发生的,这似乎将消息留在了队列中,但错误的是我的服务。重新启动我的服务将重复此过程。

理想情况下,我希望执行以下操作:

尝试处理此消息

  • 如果失败,请为该消息等待5分钟,然后重试。
  • 如果该过程失败3次,请将该消息移动到死信队列中。

服务将把死信队列中的所有消息推回到队列中,以便可以对其进行处理。

我能做到这一点吗?如果是这样的话,是怎么做的?你能给我推荐一些关于如何最好地利用WCF和MSMQ的好文章吗?

任何帮助都将不胜感激。谢谢!

一些其他信息

我在Windows XP和Windows Server 2003上使用MSMQ 3.0。不幸的是,我不能使用针对MSMQ4.0和Vista/2008的内置有害消息支持。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2008-09-17 17:36:23

SDK中有一个可能对您有用的示例。基本上,它所做的就是将一个IErrorHandler实现附加到您的服务,该实现将在WCF声明消息为“有毒”时捕获错误(即,当所有已配置的重试都已耗尽时)。该示例所做的是将消息移动到另一个队列,然后重新启动与该消息相关联的ServiceHost (因为当发现有毒消息时,它将出现故障)。

这不是一个非常漂亮的示例,但它可以是有用的。不过,这有几个限制:

1-如果您有多个端点与您的服务相关联(即通过多个队列公开),则无法知道有毒消息到达哪个队列。如果你只有一个队列,这不是问题。我还没有看到任何正式的解决方法,但我已经尝试了一种可能的替代方法,我在这里记录了这一点:http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2-一旦问题消息被移动到另一个队列,它就变成了您的责任,因此,在超时结束后,由您决定是否将其移回处理队列(或将新服务附加到该队列以处理它)。

老实说,不管是哪种情况,你在这里看到的都是一些“手工”工作,而WCF本身并不能涵盖这些工作。

我最近一直在做一个不同的项目,其中我需要显式地控制重试发生的频率,我当前的解决方案是创建一组重试队列,并基于一组计时器和一些启发式方法在重试队列和主处理队列之间手动移动消息,只需使用原始的System.Messaging内容来处理MSMQ队列。它似乎工作得很好,但如果你这样做,会有几个陷阱。

票数 9
EN

Stack Overflow用户

发布于 2008-09-17 12:29:42

我认为使用MSMQ (仅在Vista上可用),您可以这样做:

<bindings>
    <netMsmqBinding>
        <binding name="PosionMessageHandling"
             receiveRetryCount="3"
             retryCycleDelay="00:05:00"
             maxRetryCycles="3"
             receiveErrorHandling="Move" />
    </netMsmqBinding>
</bindings>

在第一次调用失败后,WCF将立即重试ReceiveRetryCount次数。批处理失败后,消息将移动到重试队列。在RetryCycleDelay分钟的延迟之后,消息从重试队列移动到端点队列,并且批处理被重试。这将重复MaxRetryCycle时间。如果所有失败的消息都根据receiveErrorHandling处理,则可以移动(毒害队列)、拒绝、丢弃或出错

顺便说一下,Juval Lowy的Progammig WCF书的第9章中有一篇关于WCF和MSMQ的好文章

票数 14
EN

Stack Overflow用户

发布于 2008-09-17 12:54:15

如果您正在使用SQL-Server,那么您应该使用分布式事务,因为MSMQ和SQL-Server都支持它。实际情况是,您将数据库写操作包装在一个TransactionScope块中,并仅在成功时才调用scope.Complete()。如果失败,那么当您的WCF方法返回时,消息将被放回队列中重试。下面是我使用的代码的精简版本:

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void InsertRecord(RecordType record)
    {
        try
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                SqlConnection InsertConnection = new SqlConnection(ConnectionString);
                InsertConnection.Open();

                // Insert statements go here

                InsertConnection.Close();

                // Vote to commit the transaction if there were no failures
                scope.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.WarnException(string.Format("Distributed transaction failure for {0}", 
                Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()),
                ex);
        }
     }

我通过将大量但已知数量的记录排队来测试这一点,让WCF启动许多线程以同时处理其中的许多线程(达到16个线程--一次从队列中删除16条消息),然后在操作过程中终止进程。当程序重新启动时,将从队列中读回消息并再次处理,就好像什么都没有发生一样,并且在测试结束时,数据库是一致的,没有丢失的记录。

分布式事务管理器在环境中存在,当您创建TransactionScope的新实例时,它会自动搜索方法调用范围内的当前事务--在将消息弹出队列并调用您的方法时,WCF应该已经创建了该事务。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/82099

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档