先放一张使用CorrelationId相关ID进行消息回调处理的流程图

  

  • 客户端启动时,它将创建一个匿名回调队列
  • 对于 RPC 请求,客户端发送一条消息,该消息具有两个属性: reply_to(设置为回调队列)和 correlation_id(设置为每个请求的唯一值)
  • 该请求被发送到 rpc_queue 队列
  • RPC 工作程序等待该队列上的请求,出现请求时,它将使用 reply_to 字段中的队列来完成工作,并将消息和结果发送回客户端
  • 客户端等待回调队列上的数据,出现消息时,它将检查 correlation_id 属性。 如果它与请求中的值匹配,则将响应返回给应用程序(TODO)

发送回调

        public void SendCallback<T>(string topic, T value, Action<byte[]> callback, byte priority = 1)
{
EnsureDeclare(topic);
var replyQueue = _model.QueueDeclare().QueueName;
var props = _model.CreateBasicProperties();
props.Priority = priority;
props.ReplyTo = replyQueue;
var correlationId = Guid.NewGuid().ToString("N");
props.CorrelationId = correlationId; //发布消息
_model.BasicPublish(_exchange, topic, props, value.GetBuf()); //创建消费者用于消息回调
var callbackConsumer = new EventingBasicConsumer(_model);
_model.BasicConsume(queue: replyQueue, autoAck: true, consumer: callbackConsumer); callbackConsumer.Received += (model, ea) =>
{
if (ea.BasicProperties.CorrelationId == correlationId)
callback(ea.Body);
};
}

消息接收,在接受消息后,通过ReplyTo来进行消息回执

        public void SetReceiveCallback(string topic, Action<byte[], IBasicProperties> received)
{
EnsureDeclare(topic);
var consumer = new EventingBasicConsumer(_model);
consumer.Received += (model, ea) =>
{
var properties = ea.BasicProperties;
var replyProerties = _model.CreateBasicProperties();
replyProerties.CorrelationId = properties.CorrelationId;
replyProerties.ReplyTo = properties.ReplyTo;
received(ea.Body, replyProerties);
_model.BasicAck(ea.DeliveryTag, false);
};
_model.BasicConsume(topic, false, consumer);
}

单元测试代码

    [Order(1)]
public class RabbitCallbackTest
{
[Fact, Order(1)]
public void ServerCallback()
{
_rabbitSvr = new Aster.Itms.Core.Data.Provider.Rabbit(new Connection()
{
Ip = "localhost",
Port = 5672,
User = "guest",
Password = "guest"
}, ""); _rabbitSvr.SetReceiveCallback("topic", ServerReceiveCommand);
} private static volatile Aster.Itms.Core.Data.Provider.Rabbit _rabbitSvr;
[Fact, Order(2)]
public void ClientCallback()
{
var _rabbitSvr = new Aster.Itms.Core.Data.Provider.Rabbit(new Connection()
{
Ip = "localhost",
Port = 5672,
User = "guest",
Password = "guest"
}, ""); string val = $"发送消息{Guid.NewGuid().ToString("N")}"; _rabbitSvr.SendCallback<string>("topic", val, ClientReceiveCommand, 1);
} private static void ClientReceiveCommand(byte[] body)
{
var result = body.To<string>(); //拿到结果再发送回去 Console.WriteLine($"接收服务端返回消息:{result}"); Assert.NotEmpty(result);
} private static void ServerReceiveCommand(byte[] body, IBasicProperties replyProps)
{
var result = body.To<string>(); Assert.NotEmpty(result); Console.WriteLine($"服务端接收:{result},CorrelationId:{replyProps.CorrelationId}"); int.TryParse(result, out int newResult); if (!string.IsNullOrEmpty(replyProps.ReplyTo))
_rabbitSvr.Send(replyProps.ReplyTo, $"{Convert.ToInt32(newResult) + 1000}", replyProps);
}
}

Rabbit使用CorrelationId进行可靠性消息回调的更多相关文章

  1. 2.RabbitMQ 的可靠性消息的发送

      本篇包含 1. RabbitMQ 的可靠性消息的发送 2. RabbitMQ 集群的原理与高可用架构的搭建 3. RabbitMQ 的实践经验   上篇包含 1.MQ 的本质,MQ 的作用 2.R ...

  2. 终于懂了:Delphi消息的Result域出现的原因——要代替回调函数的返回值!(MakeObjectInstance不会帮助处理(接收)消息回调函数的返回值)

    MakeObjectInstance应该不会帮助处理(接收)消息回调函数的返回值,可是有时候又确实需要这个返回值,这可怎么办呢?我是看到这段文字的时候,想到这个问题的: 当WM_PAINT不是由Inv ...

  3. Rabbit MQ 怎么保证可靠性、幂等性、消费顺序?

    RabbitMQ如何保证消息的可靠性 RabbitMQ消息丢失的三种情况 生产者弄丢消息时的解决方法 方法一:生产者在发送数据之前开启RabbitMQ的事务(采用该种方法由于事务机制,会导致吞吐量下降 ...

  4. Rabbit mq订阅方式获取消息并可设置持久化

    Rabbit 通过方式获取消息:订阅方式事实上是向queue注冊consumer,通过rpc向queue server发送注冊consumer的消息.rabbitMQ Server在收到消息后,依据消 ...

  5. 【mq读书笔记】客户端处理消息(回调提交到异步业务线程池,pullRequest重新入队)

    看一下客户端收到消息后的处理: MQClientAPIImpl#processPullResponse private PullResult processPullResponse( final Re ...

  6. 理解Storm可靠性消息

    看过一些别人写的, 感觉有些东西没太说清楚,个人主要以源代码跟踪,参考个人理解讲述,有错误请指正. 1基本名词 1.1 Tuple: 消息传递的基本单位.很多文章中介绍都是这么说的, 个人觉得应该更详 ...

  7. Spring Boot and Rabbit MQ 异常的时候消息的状态

    我们有一个处理消息的方法. 在处理消息的时候出现了异常,那出现异常后这个消息会怎么处理呢. 根据我们的实际情况的观察,如果出现了异常. 但是你没有捕获或者处理异常,这个消息会一直存在,并且你的系统会持 ...

  8. 专门用于消息回调窗口的窗口标识HWND_MESSAGE(创建一个非可视、没有z-order的窗口)

    HWND_MESSAGE Message-Only Windows A message-only window enables you to send and receive messages. It ...

  9. Rabbit MQ 消息确认和持久化机制

    一:确认种类 RabbitMQ的消息确认有两种.一种是消息发送确认,用来确认生产者将消息发送给交换器,交换器传递给队列的过程中消息是否成功投递.发送确认分为两步,一是确认是否到达交换器,二是确认是否到 ...

  10. RabbitMQ消息可靠性分析

    消息中间件的可靠性是指对消息不丢失的保障程度:而消息中间件的可用性是指无故障运行的时间百分比,通常用几个 9 来衡量.不存在绝对的可靠性只能尽量趋向完美.并且通常可靠性也意味着影响性能和付出更大的成本 ...

随机推荐

  1. svn把文件日期设置为最后提交的时间

    在使用svn进行checkout或update时,我想让文件的日期为提交那时的日期,这要怎样做? 说明:我是在windows下使用TortoiseSVN进行操作的 方法1.修改config [misc ...

  2. 7.1 C/C++ 实现动态数组

    动态数组相比于静态数组具有更大的灵活性,因为其大小可以在运行时根据程序的需要动态地进行分配和调整,而不需要在编译时就确定数组的大小.这使得动态数组非常适合于需要动态添加或删除元素的情况,因为它们可以在 ...

  3. LyScript 实现Hook隐藏调试器

    LyScript 插件集成的内置API函数可灵活的实现绕过各类反调试保护机制,前段时间发布的那一篇文章并没有详细讲解各类反调试机制的绕过措施,本次将补充这方面的知识点,运用LyScript实现绕过大多 ...

  4. 爆了!Sealos 三天支持 1000 个帕鲁私服

    Sealos 的帕鲁私服模板从第一天发布之后就起了 100 多个私服,第二天直接上到 500 多个,第三天直接上千,还在加速增长中.来讲讲我们只用一个晚上怎么做到上线一个专属可用区的,还有一些帕鲁实践 ...

  5. java线程池实现多任务并发执行

    Java线程池实现多任务并发执行 1️⃣ 创建一些任务来落地多任务并发执行 每一个数组里面的数据可以看成任务,或者是需要并发的业务接口, 数组与数组之间,可以看作为他们之间有血缘关系,简单来说就是: ...

  6. Leetcode刷题第五天-二分法-回溯

    215:第k个最大元素 链接:215. 数组中的第K个最大元素 - 力扣(LeetCode) em~~怎么说呢,快速选择,随机定一个目标值,开始找,左边比目标小,右边比目标大,左右同时不满足时,交换左 ...

  7. NC19429 红球进黑洞

    题目链接 题目 题目描述 在心理疏导室中有一种奇特的疏导工具,叫做红球.红球被提前分为了许多正方形小方格. 每当有人来找ATB做心理疏导时,ATB就会让他去先玩红球,然后通过红球小格方的高度来判断一个 ...

  8. NC24911 数独挑战

    题目链接 题目 题目描述 数独是一种填数字游戏,英文名叫 Sudoku,起源于瑞士,上世纪 70 年代由美国一家数学逻辑游戏杂志首先发表,名为 Number Place,后在日本流行,1984 年将 ...

  9. Vdbench 使用说明

    一. vdbench简介 vdbench是一个 I/O 工作负载生成器,用于验证数据完整性和度量直接附加和网络连接的存储的性能.它是一个免费的工具,容易使用,而且常常用于测试和基准测试. 可以使用vd ...

  10. 【Unity3D】角色控制器(CharacterController)

    1 简介 ​ 控制角色移动的组件主要有:Transform 组件.Rigidbody 组件.CharacterController 组件.Transform 组件通过控制角色位置实现移动,Rogidb ...