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. 用layer-list做一个卡片背景

    <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android=" ...

  2. XJOI3602 邓哲也的矩阵(优先队列优化DP)

    题目描述: 有一个 n×m的矩阵,现在准备对矩阵进行k次操作,每次操作可以二选一 1: 选择一行,给这一行的每一个数减去p,这种操作会得到的快乐值等于操作之前这一行的和 2: 选择一列,给这一列的每一 ...

  3. Android-ContentProvider流程

    Android-ContentProvider原理及流程 Android为什么设计出一个ContentProvider ? 答:ContentProvider的出现主要是暴露数据出去,暴露什么数据呢 ...

  4. Android-AndroidStudio Run 'app'安装APK到设备的过程

    1.AndroidStudio 点击Run ‘app’. 2.点击Run ‘app’就会将所有.class文件用SDK工具集处理成.dex, 用SDK工具集将图片/资源/布局文件/AndroidMan ...

  5. [LeetCode 题解]: palindromes

    Determine whether an integer is a palindrome. Do this without extra space. Some hints: Could negativ ...

  6. Arcgis Android 常见问题

    关于arcgis android 安装包较大的问题 如果想缩小大小,可以只保留armeabi,只是这样就不支持x86类型cpu的手机了. 可以考虑做成单独的版本,供用户下载. 即打2个包,一个供普通a ...

  7. ASP.NET Core ASP.NET Core+MVC搭建及部署

    ASP.NET Core+MVC搭建及部署 一.创建项目: 1.选择ASP.NET Core Web Application(.NET Core) 注意框架 2.选择Web Application: ...

  8. 【Selenium专题】 FAQ_对象识别_Compound class names are not supported

    测试代码 public void login(){ WebDriver driver = new ChromeDriver(); driver.get("http://IP:Port/cli ...

  9. Crash的数字表格

    Crash的数字表格 求\(\sum_{i=1}^N\sum_{j=1}^Mlcm(i,j)\) 解 设\(N<M\),显然有 \[\sum_{i=1}^N\sum_{j=1}^M\frac{i ...

  10. 模拟实现strstr和strrstr

    strstr函数用于判断str2是否是str1的子串,如果是,则返回str2在str1中首次出现位置的地址,如果不是则返回NULL.其模拟实现代码如下:#include<iostream> ...