20140310补充:

  rabbitmq有requeue属性,可以选择消息是否返回队列,另,本文的解决方式非常之山寨,只能应用于发送和接收方式。  

  这几天在折腾消息队列,在.Net环境下有基于RabbitMQ有很多有API的选择,最后选择了比较简单的EasyNetQ(http://easynetq.com/)

  在测试使用的时候发现一个问题,对于处理错误的消息,EasyNetQ默认会放到一个错误队列中并提供了一个工具可以对错误队列的消息进行重新分发。RabiitMQ是有一个事务功能的,但是貌似在EasyNetQ的实现中,没有发现相关的操作方式

  现在的需求是,在某种特定的情况下,需要将处理不成功的消息,保留在消息原队列

  做了一个变通处理,出现错误消息的时候,将其再送回原队列。从客户端上可以直接send回队列,但这样不是一个很好的方式

  研究了一下EasyNetQ的相关代码,发现其定义了一个IConsumerErrorStrategy接口,我们只要自己自行实现,并注册一个自定义方法就可以

  ComponentRegistration.cs原注册方法相关,默认错误消息处理方式在DefaultConsumerErrorStrategy.cs中

     public class ComponentRegistration
{
public static void RegisterServices(IContainer container)
{
Preconditions.CheckNotNull(container, "container"); // Note: IConnectionConfiguration gets registered when MQContext.CreateBus(..) is run.
#region DefaultConsumerErrorStrategy
container
.Register(_ => container)
.Register<IMessageQueueQLogger, ConsoleLogger>()
.Register<ISerializer, JsonSerializerN>()
.Register<IConventions, Conventions>()
.Register<IEventBus, EventBus>()
.Register<ITypeNameSerializer, TypeNameSerializer>()
.Register<Func<string>>(x => CorrelationIdGenerator.GetCorrelationId)
.Register<IClusterHostSelectionStrategy<ConnectionFactoryInfo>, DefaultClusterHostSelectionStrategy<ConnectionFactoryInfo>>()
.Register<IConsumerDispatcherFactory, ConsumerDispatcherFactory>()
.Register<IPublishExchangeDeclareStrategy, PublishExchangeDeclareStrategy>()
.Register<IPublisherConfirms, PublisherConfirms>()
.Register<IConsumerErrorStrategy, DefaultConsumerErrorStrategy>()
.Register<IHandlerRunner, HandlerRunner>()
.Register<IInternalConsumerFactory, InternalConsumerFactory>()
.Register<IConsumerFactory, ConsumerFactory>()
.Register<IConnectionFactory, ConnectionFactoryWrapper>()
.Register<IPersistentChannelFactory, PersistentChannelFactory>()
.Register<IClientCommandDispatcherFactory, ClientCommandDispatcherFactory>()
.Register<IHandlerCollectionFactory, HandlerCollectionFactory>()
.Register<IAdvancedBus, RabbitAdvancedBus>()
.Register<IRpc, Rpc>()
.Register<ISendReceive, SendReceive>()
.Register<IBus, RabbitBus>();
#endregion
}
}

  对DefaultConsumerErrorStrategy的代码进行研究后发现,EasyNetQ是产生一个处理错误消息队列的Exchanges,将消息二次封装后推送到默认的错误队列

  只要将消息队列改为源消息队列,取消消息二次封装,直接推送到队列

  队列绑定

         private string DeclareErrorExchangeAndBindToDefaultErrorQueue(IModel model, ConsumerExecutionContext context)
{
var originalRoutingKey = context.Info.RoutingKey; return errorExchanges.GetOrAdd(originalRoutingKey, _ =>
{
var exchangeName = conventions.ErrorExchangeNamingConvention(context.Info);
model.ExchangeDeclare(exchangeName, ExchangeType.Direct, durable: true);
//更改第一个参数
model.QueueBind(originalRoutingKey, exchangeName, originalRoutingKey);
return exchangeName;
});
}

  消息处理

         public virtual PostExceptionAckStrategy HandleConsumerError(ConsumerExecutionContext context, Exception exception)
{
Preconditions.CheckNotNull(context, "context");
Preconditions.CheckNotNull(exception, "exception"); try
{
Connect(); using (var model = connection.CreateModel())
{
var errorExchange = DeclareErrorExchangeQueueStructure(model, context);
var messageBody = context.Body;
var properties = model.CreateBasicProperties();
context.Properties.CopyTo(properties);
properties.Type = context.Properties.Type;
//消息持久化
properties.SetPersistent(true); model.BasicPublish(errorExchange, context.Info.RoutingKey, properties, messageBody); }
}
catch (Exception unexpectedException)
{
// Something else unexpected has gone wrong :(
logger.ErrorWrite("EasyNetQMessageQueue Consumer Error Handler: Failed to publish error message\nException is:\n"
+ unexpectedException);
}
return Consumer.PostExceptionAckStrategy.ShouldAck;
}

  因为EasyNetQ在CreateBus的时候就会将相关事件注册,所以我们只需最后自行在config中加入有关配置,在注册事件的位置加入判断即可让异常抛回

  由于刚接触RabbitMQ,对于一些概念的理解可能还不是非常到位,这是我目前所能找到的解决方案

  当然可能以后的版本中,EasyNetQ会加入对事务的操作,现在EasyNetQ支持了一种叫Publisher Confirms的方法,貌似还是不是我想要的

												

EasyNetQ自定义异常消息处理的更多相关文章

  1. Web API应用架构在Winform混合框架中的应用(2)--自定义异常结果的处理

    在上篇随笔<Web API应用架构在Winform混合框架中的应用(1)>中我介绍了关于如何在Winfrom里面整合WebAPI,作为一个新型数据源的接入方式,从而形成了三种不同的数据提供 ...

  2. .NET操作RabbitMQ组件EasyNetQ使用中文简版文档。

    本文出自EasyNetQ官方文档,内容为自己理解加翻译.文档地址:https://github.com/EasyNetQ/EasyNetQ/wiki/Quick-Start EasyNetQ简介 Ea ...

  3. 【框架学习与探究之消息队列--EasyNetQ(1)】

    前言 本文欢迎转载,实属原创,本文原始链接地址:http://www.cnblogs.com/DjlNet/p/7603554.html 废话 既然都是废话了,所以大家就可以跳过了,这里是博主有事没事 ...

  4. 使用EasyNetQ组件操作RabbitMQ消息队列服务

    RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现,是实现消息队列应用的一个中间件,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合, ...

  5. NET操作RabbitMQ组件EasyNetQ

    NET操作RabbitMQ组件EasyNetQ使用中文简版文档. 本文出自EasyNetQ官方文档,内容为自己理解加翻译.文档地址:https://github.com/EasyNetQ/EasyNe ...

  6. RabbitMQ学习系列四-EasyNetQ文档跟进式学习与实践

    EasyNetQ文档跟进式学习与实践 https://www.cnblogs.com/DjlNet/p/7603554.html 这里可能有人要问了,为什么不使用官方的nuget包呐:RabbitMQ ...

  7. NetCore基于EasyNetQ的高级API使用RabbitMq

    一.消息队列 消息队列作为分布式系统中的重要组件,常用的有MSMQ,RabbitMq,Kafa,ActiveMQ,RocketMQ.至于各种消息队列的优缺点比较,在这里就不做扩展了,网上资源很多. 更 ...

  8. EasyNetQ使用(九)【非泛型的发布&订阅扩展方法,发生错误的情况 】

    自从EasyNetQ第一个版本开始,它就可以发布/订阅特定类型的消息. bus.Subscribe<MyMessage>("subscriptionId", x =&g ...

  9. EasyNetQ异常处理

    代码下载 https://download.csdn.net/download/u010312811/11252093 官方Demo https://github.com/EasyNetQ/EasyN ...

随机推荐

  1. 编写高质量代码改善C#程序的157个建议——建议90:不要为抽象类提供公开的构造方法

    建议90:不要为抽象类提供公开的构造方法 首先,抽象类可以有构造方法.即使没有为抽象类指定构造方法,编译器也会为我们生成一个默认的protected的构造方法.下面是一个标准的最简单的抽象类: abs ...

  2. 2、Semantic-UI之网格布局

    2.1 网格布局   在semantic-ui中提供了16个网格,使用class="column",当然也可以通过数字来表示当前网格大小.   在Semantic-UI中定义的网格 ...

  3. Linq分组操作之GroupBy,GroupJoin扩展方法源码分析

    Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...

  4. Spring.NET 整合Nhibernate

    因为最近无意中学了AOP ,所以想一探究竟,看看.net里这个Spring.Net 到底是怎么回事,请有需要的童鞋往下,不需要的请alt+w.因为是先配置的 Nhibernate 所以就从这个开始.开 ...

  5. Android 工具类大全

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38965311 1.日志工具类L.java package com.zhy.uti ...

  6. Jenkins Pipeline+Maven+Gitlab持续集成构建

    http://www.cnblogs.com/xiaodai12138/p/9996995.html

  7. Centos iptables防火墙设置

    iptables的基本语法格式 iptables [-t 表名] 命令选项 [链名] [条件匹配] [-j 目标动作或跳转]说明:表名.链名用于指定iptables命令所操作的表和链,命令选项用于指定 ...

  8. Decoding VOX Files in C# (Converting VOX Files to WAV Files)

    I wrote a C# class to decode VOX files into WAV files. It follows the Dialogic ADPCM specificationst ...

  9. JavaScript类型检测汇总

        曾经我以为JavaScript中的类型检测只要使用 typeof 或 instanceof 就可以通通解决.后来我发现我是too young too naive啊!早说过JavaScript是 ...

  10. Apache 中httpd.conf文件配置详解(转载)

    httpd.conf文件配置详解   Apache的基本设置主要交由httpd.conf来设定管理,我们要修改Apache的相关设定,主要还是通过修改httpd.cong来实现.下面让我们来看看htt ...