EasyNetQ使用(三)【Publish与Subcribe】

EasyNetQ支持的最简单的消息模式是发布/订阅.这个模式是一个极好的方法用来解耦消息提供者和消费者。消息发布者只要简单的对世界说,“这里有些事发生” 或者 “我现在有一个信息”。它不关心有没有人监听,或者接收者是谁,或者接收者在那里。我们能够添加和移除特定类型的消息的订阅者,不需发布者做任何的重新配置。我们也能够有多个发布者发布相同的消息,添加和删除发布者也不用其他的发布者或者订阅者做任何重新配置。

EasyNetQ发布消息(假定你已经重建了一个IBus实例)

  1. 创建你自己的消息实例,可以是任何可序列化的 .NET 类型。
  2. 调用IBus上的Publish方法,并传入你的消息实例。

代码如下:

var message = new MyMessage{ Text = "Hello Rabbit" };
bus.Publish(message);

为确保消息投递成功,请看Publisher Confirms.

发布者和订阅者之间彼此是不知道对方的。发布者简单的对世界说“这儿有事情发生”,订阅者告诉世界“我关心这种事儿的发生”。在这个模型中这是很好的,没有人关心特定的事件。可能有一个订阅者关心这个消息,也可能有200个,或者没有人关心它。发布者不应该关心EasyNetQ对这个消息模式的实现。假如你开始去发布消息,而没有任何订阅者曾经定义此消息,那么这个消息就简单的消失了。这是我们的设计意图。



一个EasyNetQ订阅者订阅一种消息类型(消息类为.NET 类型)。通过调用Subcribe方法一旦对一个类型设置了订阅,一个持久化队列就会在RabbitMQ broker上被创建,这个类型的任何消息都会被发送到这个队列上。订阅者无论什么时候连接上,RabbitMQ都将会将消息从队列中发送给订阅者。

不管消息什么时候送达到,订阅这个消息的订阅者需要给RabbitMQ一个可执行的操作。我们通过传递一个订阅代理:

bus.Subscribe<MyMessage>("my_subscription_id", msg => Console.WriteLine(msg.Text));
  • 1

现在每一次MyMessage实例被发送后,EasyNetQ将会调用我们的代理,打印这个消息的Text属性到控制台。

你传给订阅的订阅Id是重要的。 EasyNetQ将会在RabbitMQ Broker上为特定的消息类型的和订阅id的组合创建唯一的队列。

每一次调用Subscribe方法会创建一个新的队列消费者。如果你用相同的消息和订阅id调用Subscribe两次,你将会创建两个消费者去消费同一个队列。然后RabbitMQ将会依次连续轮询消息给每一个消费者。这种可伸缩性和工作分担是非常棒的。比如说,你创建了一个处理特殊消息的服务,但是他已经超负荷工作了。简单的创建一个新的服务实例(在同一个机器上,或者不同的机器上),不用配置任何东西,你自动就得到了伸缩性。

假如相同的消息类型,用不同的订阅id调用了两次Subscribe,你将创建两个队列,每一个队列有自己的消费者。每一个消息的副本将会路由到每一个队列,因此不同的消费者都将得到所有消息(这个类型的)。假如你有几个不同的服务都关心相同类型的消息,这这样很好。
写订阅回调委托时的注意事项

通过EasyNetQ订阅到一个来至队列的消息,他们被放置在内存队列中。一个单独线程循环对垒得到消息,调用他们的委托方法。因为在一个独立线程上一个委托一次处理一个消息,你应该避免长时间的同步的IO操作。应该尽快从委托返回控制。

使用异步订阅 SubscribeAsync

SubscribeAsync 允许你的订阅者委托到一个能立即返回的Task,然后异步的执行长时间IO操作。一但长时间运行的订阅完成后,就简单的完成这个任务。下面的例子,我们请求一个web service使用一个异步IO操作(DownloadStringTask)。当这个task完成事,写一行信息到控制台。

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(() =>
             {
                 //这里执行一些操作
                 //如果这里有一个异常,那么在这个Task执行完毕后,这个异常会作为结果返回,
                 // 然后任务将继续执行下去。
             }).ContinueWith(task =>
             {
                 if ( task.IsCompleted && ! task.IsFaulted)
                 {
                     // 一切都很好
                 }
                 else
                 {
                     // 不要Catch 异常,否则异常会进一步被嵌套,结果会被发送到默认的错误队列
                     throw new EasyNetQException("Message processing exception - look in t  the default error quenue(broker)");
                 }
             }));

取消订阅

所有的订阅都会返回一个ISubscriptionResult接口实例。它包含属性有订阅底层被IConsumer使用的IExchaneIQueue,如果你需要使用更高级的API IAdvancedBus更好的去处理,这会变为可能。

你能够在任何时间取消一个订阅者,通过调用ISubscriptionResult实例上的Dispose方法,或者在它之上的 ConsumerCancellation属性。

var subscriptionResult = bus.Subscribe<MyMessage>("sub_id", MyHandler);

...

subscriptionResult.Dispose();
// 这个等价与 subscriptionResult.ConsumerCancellation.Dispose();

这将停止EasyNetQ对队列的消费,并且关闭这个消费者的channel

注意:IBusIAndvancedBusdispose,可能够取消所有消费者,并关闭对RabbitMQ的连接。

不要在消息处理器中调用 subscriptionResult.Dispose()。这将在EasyNetQ ACK 消息时,在消费者的channelsubscriptionResult.Dispose()调用关闭Channel之间,创建一个竞争状态。由于EasyNetQ的内部架构这些将会在不同的线程被调用,还有时间上的不确定性。

原文地址:https://www.cnblogs.com/lhxsoft/p/11881076.html

时间: 2024-10-07 05:47:44

EasyNetQ使用(三)【Publish与Subcribe】的相关文章

RabbitMQ官方教程三 Publish/Subscribe(GOLANG语言实现)

在上一个教程中,我们创建了一个工作队列. 工作队列背后的假设是,每个任务都恰好交付给一个worker处理. 在这一部分中,我们将做一些完全不同的事情-我们将消息传达给多个消费者. 这种模式称为"发布/订阅". 为了说明这种模式,我们将构建一个简单的日志记录系统. 它由两个程序组成-第一个程序将发出日志消息,第二个程序将接收并打印它们. 在我们的日志系统中,消费者每个运行副本都将获得消息. 这样,我们将能够运行一个消费者并将日志写入到磁盘. 同时我们将能够运行另一个消费者并在屏幕上查看日

RabbitMQ(三) -- Publish/Subscribe

RabbitMQ(三) -- Publish/Subscribe `rabbitmq`支持一对多的模式,一般称为发布/订阅.也就是说,生产者产生一条消息后,`rabbitmq`会把该消息分发给所有的消费者. Exchanges 之前的教程中,仅仅使用了基本的消息模型: 生产者产生消息 把消息添加到消息队列 消费者接收消息 而在`rabbitmq完整的消息模型`中,并不是这样的.事实上,生产者并不知道消息是否发送到队列,而是把消息直接发送给`Exchanges`. `Exchanges`的功能理解

mqtt协议-broker之moqutte源码研究三之PUBLISH报文处理

先简单说明一下,对于mqtt是个双向通信的过程,也就是说,他既允许client向broker发布消息,同时也允许broker向client发布消息 public void processPublish(Channel channel, MqttPublishMessage msg) { final MqttQoS qos = msg.fixedHeader().qosLevel(); final String clientId = NettyUtils.clientID(channel); LO

RabbitMQ学习(三).NET Client之Publish/Subscribe

3 Publish/Subscribe Sending messages to many consumers at once Python | Java | Ruby | PHP| C# 转载请注明出处:jiq?钦's technical Blog Publish/Subscribe (using the .NET Client) 前面的教程我们已经学习了如何创建工作队列,工作队列背后的假设是每一个任务都被准确地递送给一个worker进行处理.这里我们将介绍完全不同的模式,即一个消息可以递送给多

RabbitMQ学习第三记:发布/订阅模式(Publish/Subscribe)

工作队列模式是直接在生产者与消费者里声明好一个队列,这种情况下消息只会对应同类型的消费者. 举个用户注册的列子:用户在注册完后一般都会发送消息通知用户注册成功(失败).如果在一个系统中,用户注册信息有邮箱.手机号,那么在注册完后会向邮箱和手机号都发送注册完成信息.利用MQ实现业务异步处理,如果是用工作队列的话,就会声明一个注册信息队列.注册完成之后生产者会向队列提交一条注册数据,消费者取出数据同时向邮箱以及手机号发送两条消息.但是实际上邮箱和手机号信息发送实际上是不同的业务逻辑,不应该放在一块处

RabbitMQ官方中文入门教程(PHP版) 第三部分:发布/订阅(Publish/Subscribe)

发布/订阅 在上篇教程中,我们搭建了一个工作队列.每个任务之分发给一个工作者(worker).在本篇教程中,我们要做的之前完全不一样——分发一个消息给多个消费者(consumers).这种模式被称为“发布/订阅”. 为了描述这种模式,我们将会构建一个简单的日志系统.它包括两个程序——第一个程序负责发送日志消息,第二个程序负责获取消息并输出内容. 在我们的这个日志系统中,所有正在运行的接收方程序都会接受消息.我们用其中一个接收者(receiver)把日志写入硬盘中,另外一个接受者(receiver

RabbitMQ学习系列(三): C# 如何使用 RabbitMQ

上一篇已经讲了Rabbitmq如何在Windows平台安装,还不了解如何安装的朋友,请看我前面几篇文章:RabbitMQ学习系列一:windows下安装RabbitMQ服务 , 今天就来聊聊 C# 实际开发的过程中,怎么调用 用RabbitMQ. 一.客户端 RabbitMQ 有很多客户端API,都非常的好用.我们在一边,一直用的都是 EasyNetQ,所以这里的 demo 只介绍 EasyNetQ 客户端实现.其他的客户端,大家自己去研究吧. EasyNetQ 是一个易于使用的RabbitMQ

简单易用的.NET免费开源RabbitMQ操作组件EasyNetQ解析

对于目前大多的.NET项目,其实使用的技术栈都是差不多,估计现在很少用控件开发项目的了,毕竟一大堆问题.对.NET的项目,目前比较适合的架构ASP.NET MVC,ASP.NET WebAPI,ORM(较多Dapper.NET或者其扩展,稍大一些的项目用EF等等),为了提高速度也会采用缓存(.NET自带的Memcache,或者Redis),请求较多的项目,使用Nginx做负载均衡和使用队列等等. 上面简单的介绍一下.NET的项目的技术架构,具体的技术根据具体的需求做出选择.介绍到队列,很多人都会

NET操作RabbitMQ组件EasyNetQ

NET操作RabbitMQ组件EasyNetQ使用中文简版文档. 本文出自EasyNetQ官方文档,内容为自己理解加翻译.文档地址:https://github.com/EasyNetQ/EasyNetQ/wiki/Quick-Start EasyNetQ简介 EasyNetQ是基于官方.NET组件RabbitMQ.Client 的又一层封装,使用起来更加方便,开发者不用关心具体队列声明,路由声明等细节,几句简单代码即可发送消息到队列,接收消息也很简单,下面将简单介绍EasyNetQ的使用方法.