3,EasyNetQ-发布/订阅
一、发布
在发布/订阅模式中的角色是彼此陌生的。 一个发布者只是向世界说这个已经发生了,一位订阅者告诉世界“我在乎这个”。 在这个模型中,没有人关心特定的事件是很好的。 消息可能有一个订阅者,可能有200个,或者可能没有。 发布者不应该关心。 EasyNetQ实现这种模式。 如果您开始发布,并且没有订阅者已经开始,那么您的消息就会消失。 这是设计(先订阅,后发布,如果现发布,则消息会丢失)。
代码:
var message = new MyMessage { Text = "Hello Rabbit" };
bus.Publish(message);
二、订阅
EasyNetQ用户订阅消息类型(消息类的.NET类型)。 一旦通过调用Subscribe方法设置了类型的订阅,就会在RabbitMQ代理上创建一个持久性队列,并且任何类型的消息将被放置在队列中。 RabbitMQ将在连接时将队列中的任何消息发送给用户。
要订阅一个消息,我们需要给EasyNetQ一个消息到达时执行的操作。 我们通过订阅一个委托来做到这一点:
bus.Subscribe<MyMessage>("my_subscription_id", msg => Console.WriteLine(msg.Text));
现在每次发布MyMessage的一个实例,EasyNetQ将会调用我们的代理,并将消息的Text属性打印到控制台。
您传递给订阅的订阅ID很重要。 EasyNetQ将针对消息类型和订阅ID的每个独特组合在RabbitMQ代理上创建一个唯一的队列(消息类型+订阅ID=唯一的队列)。
每个对Subscribe的调用都会创建一个新的队列消费者。 如果您使用相同的消息类型和订阅ID来呼叫两次订阅,则将创建两个消费者从同一个队列中消费的消费者。 然后,RabbitMQ将轮流向每个消费者循环连续的消息。 这对扩展和工作分享非常有用。 假设您已经创建了处理特定消息的服务,但是工作正在重载。 只需启动该服务的新实例(在同一台机器上或另一台机器上),而无需配置任何内容,就可以自动缩放。
如果您使用不同的订阅ids但是相同的消息类型来呼叫两次订阅,那么您将创建两个队列,每个队列都有自己的消费者。 给定类型的每个消息的副本将被路由到每个队列,因此每个消费者将获得所有消息(该类型的消息)。 如果您有几个不同的服务,那些都关心相同的信息类型,这是非常好的。
写订阅回调委托时的注意事项
当从通过EasyNetQ订阅的队列接收到消息时,它们被放置在内存队列中。 一个线程坐在循环中,从队列中获取消息并调用其Action代理。 由于代理在一个线程上一次处理一次,所以您应该避免长时间运行的同步IO操作。 尽快从委托返回控制。
使用异步订阅
异步订阅允许您的用户委托立即返回任务,然后异步执行长时间运行的IO操作。 一旦长时间运行的订阅完成,只需完成任务。 在下面的示例中,我们使用异步IO操作(DownloadStringTask)向Web服务发出请求。 当任务完成时,我们在控制台上写一行。
bus.SubscribeAsync<MyMessage>("subscribe_async_test", message =>
new WebClient().DownloadStringTask(new Uri("http://localhost:1338/?timeout=500"))
.ContinueWith(task =>
Console.WriteLine("Received: '{0}', Downloaded: '{1}'",
message.Text,
task.Result)));
另一个例子会导致异常被抛出,如果有故障,那么会导致消息被放置在默认的错误队列上:
_bus.SubscribeAsync<MessageType>("Queue_Identifier",
message => Task.Factory.StartNew(() =>
{
//在这里执行一些操作
//如果有异常,则会导致任务完成,但任务发生错误
//在下面的继续处理
}).ContinueWith(task =>
{
if (task.IsCompleted && !task.IsFaulted)
{
// 一切都奏效了
}
else
{
// 不要抓住这一点,它被进一步上升到层次结构,并导致发送到默认错误队列
throw new EasyNetQException("Message processing exception - look in the default error queue (broker)");
}
}));
取消订阅
所有的订阅方法返回一个ISubscriptionResult。 它包含描述底层IConsumer使用的IExchange和IQueue的属性,如果需要,可以使用高级API IAdvancedBus进一步操作这些属性。
您可以随时通过在ISubscriptionResult实例或其ConsumerCancellation属性上调用Dispose来取消订户:
var subscriptionResult = bus.Subscribe<MyMessage>("sub_id", MyHandler);
...
subscriptionResult.Dispose();
// 这相当于 subscriptionResult.ConsumerCancellation.Dispose();
这将阻止EasyNetQ从队列中消费,并关闭消费者的频道。
请注意,处理IBus或IAdvancedBus实例也将取消所有消费者并关闭与RabbitMQ的连接。
不要在消息处理程序中调用subscriptionResult.Dispose()。 这将在EasyNetQ ACK消费者频道上的消息与subscriptionResult.Dispose()调用关闭该通道之间创建竞争条件。 由于EasyNetQ的内部架构,这些调用将在不同的线程上被调用,并且时序不是确定性的。
3,EasyNetQ-发布/订阅的更多相关文章
- easynetq发布订阅demo实现注意事项
最近开始在项目中使用easynetq,大概了解了下api,在网上看了下示例,结果没有一个运行成功的,一个最简单的发布订阅都没有成功.我是直接运行起来别人的示例,不应该啊,后来一直分析一直分析,最后发现 ...
- 【EasyNetQ】- 发布/订阅模式
EasyNetQ支持的最简单的消息传递模式是发布/ 订阅.这种模式是消除消费者信息提供者的绝佳方式.出版商简单地向全世界说,“这已经发生了”或“我现在有了这些信息”.它不关心是否有人正在倾听,他们可能 ...
- EasyNetQ使用(九)【非泛型的发布&订阅扩展方法,发生错误的情况 】
自从EasyNetQ第一个版本开始,它就可以发布/订阅特定类型的消息. bus.Subscribe<MyMessage>("subscriptionId", x =&g ...
- 17-EasyNetQ:非泛型的发布&订阅扩展方法
自从EasyNetQ第一个版本开始,它就可以发布/订阅特定类型的消息. bus.Subscribe<MyMessage>("subscriptionId", x =&g ...
- RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用
本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Re ...
- 15天玩转redis —— 第九篇 发布/订阅模式
本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...
- 第五章 --- 关于Javascript 设计模式 之 发布-订阅模式
先来个最简单的 发布订阅模式 document.body.addEventListener('click',function(){ alert(123); }); document.body.clic ...
- 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载
一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...
- 分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载
一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用 ...
- NetMQ(三): 发布订阅模式 Publisher-Subscriber
ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...
随机推荐
- Java基础-配置开发环境-安装JDK
Java基础-配置开发环境-安装JDK 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.计算机基础知识 1>.计算机的组成 计算机有硬件与软件组成. 2>.硬件: 硬 ...
- 如何通过卡面标识区分SD卡的速度等级
现在很多设备都可以插存储卡,而比较流行的就是SD(Secure Digital Memory Card)卡和Micro SD(原名TF,Trans-flash Card )卡,这两种卡主要就是尺寸不同 ...
- POJ - 3026 Borg Maze(最小生成树)
https://vjudge.net/problem/POJ-3026 题意 在一个y行 x列的迷宫中,有可行走的通路空格’ ‘,不可行走的墙’#’,还有两种英文字母A和S,现在从S出发,要求用最短的 ...
- Flex 经验笔记一
Module页面嵌套子Module页面直接用标签嵌入是不行的,无法显示出来,需要用到 ModuleManager 使用ModuleInfo 的 addEventListener 判断当子Module ...
- python中的__enter__ __exit__
我们前面文章介绍了迭代器和可迭代对象,这次介绍python的上下文管理.在python中实现了__enter__和__exit__方法,即支持上下文管理器协议.上下文管理器就是支持上下文管理器协议的对 ...
- MongoDB 之 数据类型 最无聊! But 最有用! MongoDB - 3
MongoDB的新篇章开始啦 - 数据类型 https://www.cnblogs.com/xuzhaocai/p/8048177.html 一.MongoDB 之 丰富多彩的数据类型世界 首先我们要 ...
- 递归&冒泡&装饰器
递归 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数. #lambda: func = lambda x,y:9+x 参数:x,y 函数体:9+x 函数名:func ...
- Linux内核源码分析--内核启动之(2)Image内核启动(汇编部分)(Linux-3.0 ARMv7) 【转】
转自:http://blog.chinaunix.net/uid-25909619-id-4938389.html 在完成了zImage自解压之后,就跳转到了解压后的内核(也就是vmlinux的bin ...
- Vue零散知识点
1.vue中的<router-view></router-view>的作用,它是和vue的路由相结合的,它的作用是将路由匹配到的组件渲染在里面.比如说你要跳转,如何没有< ...
- Java基础90 MySQL触发器
1.创建触发器 CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt ...