一、发布

在发布/订阅模式中的角色是彼此陌生的。 一个发布者只是向世界说这个已经发生了,一位订阅者告诉世界“我在乎这个”。 在这个模型中,没有人关心特定的事件是很好的。 消息可能有一个订阅者,可能有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-发布/订阅的更多相关文章

  1. easynetq发布订阅demo实现注意事项

    最近开始在项目中使用easynetq,大概了解了下api,在网上看了下示例,结果没有一个运行成功的,一个最简单的发布订阅都没有成功.我是直接运行起来别人的示例,不应该啊,后来一直分析一直分析,最后发现 ...

  2. 【EasyNetQ】- 发布/订阅模式

    EasyNetQ支持的最简单的消息传递模式是发布/ 订阅.这种模式是消除消费者信息提供者的绝佳方式.出版商简单地向全世界说,“这已经发生了”或“我现在有了这些信息”.它不关心是否有人正在倾听,他们可能 ...

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

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

  4. 17-EasyNetQ:非泛型的发布&订阅扩展方法

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

  5. RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用

    本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Re ...

  6. 15天玩转redis —— 第九篇 发布/订阅模式

    本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果 ...

  7. 第五章 --- 关于Javascript 设计模式 之 发布-订阅模式

    先来个最简单的 发布订阅模式 document.body.addEventListener('click',function(){ alert(123); }); document.body.clic ...

  8. 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载

    一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...

  9. 分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载

    一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已经完成,在通常的情况下,开发人中都是在使用者B所使用 ...

  10. NetMQ(三): 发布订阅模式 Publisher-Subscriber

    ZeroMQ系列 之NetMQ 一:zeromq简介 二:NetMQ 请求响应模式 Request-Reply 三:NetMQ 发布订阅模式 Publisher-Subscriber 四:NetMQ ...

随机推荐

  1. Jsp使用遍历List集合

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  2. Spring RedisTemplate操作-List操作(4)

    @Autowired @Resource(name="redisTemplate") private RedisTemplate<String, String> rt; ...

  3. Redis 学习小记

    由于是学习笔记,我就不来各种啰嗦,介绍这个介绍那个,也不上交给国家,或者各种对比,相信如果你真心用 redis 的话,就不会去跟 MySql,Memcached,MongoDB 等做对比了. 我原先用 ...

  4. Guava HashMultiMap(MultiMap)反转映射

    (一)MultiMap 多重map,一个key可以对应多个值(多个值放在一个list中),可用于分组 举例: Multimap<String, Integer> map = HashMul ...

  5. 第13月第16天 ios keywindow

    1. 在弹出层弹出后keywindow已改变 http://www.jianshu.com/p/4695d7efa20b

  6. MongoDB 之 Array Object 的特殊操作 MongoDB - 6

    相比关系型数据库, Array [1,2,3,4,5] 和 Object { 'name':'DragonFire' } 是MongoDB 比较特殊的类型了 特殊在哪里呢?在他们的操作上又有什么需要注 ...

  7. 工具类。父类(Pom文件)

    ego_parent(pom文件) <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="ht ...

  8. 使用Sysmon和Splunk探测网络环境中横向渗透

    当前很难在网络中探测攻击者横向渗透,其中原因有很难获取必要的日志和区别正常与恶意行为.本篇文章介绍通过部署Sysmon并将日志发送到SIEM来探测横向渗透. 工具: Sysmon + Splunk l ...

  9. C#并行计算 Parallel.Foreach&Parallel.For

    Parallel.For(int fromInclude, int toExclude, Action<int> body) 栗子: Parallel.For(0, 10, (i) =&g ...

  10. OpenLayers 3 之 地图图层数据来源(ol.source)详解

    原文地址 source 是 Layer 的重要组成部分,表示图层的来源,也就是服务地址.除了在构造函数中制定外,可以使用 layer.setSource(source) 稍后指定.一.包含的类型 ol ...