.NET6 RabbitMQ自动重连

序言

        在技术领域,不断学习和探索是保持竞争力的关键。最近,我重新开始了对RabbitMQ的研究,这个过程让我又收获了许多新的知识和技能,我觉得有必要记录下来,以便将来回顾和分享。

问题引出

        RabbitMQ是一款开源的消息队列中间件,它提供了高效、可靠、灵活的通信机制,广泛应用于分布式系统中。然而,有时候在使用RabbitMQ时会遇到连接断开的问题,这可能会导致消息传递中断和应用程序的不可用性。

问题分析

        当使用RabbitMQ时,可能会遇到以下几种情况导致连接断开的问题:

1.网络问题:网络中断、防火墙设置等问题可能导致RabbitMQ连接断开。

2.长时间空闲:如果连接在一段时间内没有进行任何通信,RabbitMQ可能会自动关闭连接。

3.RabbitMQ服务器问题:RabbitMQ服务器可能会因为负载过高或其他原因主动关闭连接。

解决方案

        虽然RabbitMQ.Client库,有心跳机制,有断线重连机制,但是在网络断开的时候,并不能重连。

        下面这段代码经过本人验证有效,可以解决上面的问题。

using RabbitMQ.Client.Events;
using RabbitMQ.Client;
using System.Text;
using RabbitMQDemo.Shared;
using System.Collections.Concurrent;
using RabbitMQ.Client.Exceptions;

namespace RabbitMQConsumerDemo
{
    public class RabbitMQRpcClientHandler
    {
        /// <summary>
        /// 定义一个静态变量来保存类的实列
        /// </summary>
        private static RabbitMQRpcClientHandler? _uniqueInstance;

        /// <summary>
        /// 定义一个标识确保线程同步
        /// </summary>
        private static readonly object _locker = new();

        /// <summary>
        /// Main entry point to the RabbitMQ .NET AMQP client API. Constructs RabbitMQ.Client.IConnection instances.
        /// </summary>
        private static IConnectionFactory? _factory;

        /// <summary>
        /// Main interface to an AMQP connection.
        /// </summary>
        private IConnection? _connection;

        /// <summary>
        /// 发送通道(发送通道及接收通道分开,避免互相影响,导致整个服务不可用)
        /// </summary>
        private IModel? _sendChannel;

        /// <summary>
        /// 接收通道(发送通道及接收通道分开,避免互相影响,导致整个服务不可用)
        /// </summary>
        private IModel? _listenChannel;

        /// <summary>
        /// 监听消费者
        /// </summary>
        private EventingBasicConsumer? _listenConsumer;

        /// <summary>
        /// 响应消费者
        /// </summary>
        private EventingBasicConsumer? _replyConsumer;

        /// <summary>
        /// RabbitMQ 主机域名
        /// </summary>
        private readonly string _defaultRabbitMQHostName = "127.0.0.1";

        /// <summary>
        /// RabbitMQ 服务器端口, 默认 5672, 网页监控页面是 15672
        /// </summary>
        private readonly int _defaultRabbitMQPort = 5672;

        /// <summary>
        /// RabbitMQ 用户名, 默认 guest
        /// </summary>
        private readonly string _defaultRabbitMQUserName = "guest";

        /// <summary>
        /// RabbitMQ 密码, 默认 guest
        /// </summary>
        private readonly string _defaultRabbitMQPassword = "guest!";

        /// <summary>
        /// 虚拟主机
        /// </summary>
        private readonly string _defaultRabbitMQVirtualHost = "/";

        /// <summary>
        /// 交换机
        /// </summary>
        private readonly string _exchangeName = "";

        /// <summary>
        /// 数据监控队列
        /// </summary>
        private readonly string _listenQueueName = "queue.listen.test";

        /// <summary>
        /// 指令响应队列
        /// </summary>
        private string _replyQueueName = string.Empty;

        /// <summary>
        /// 注册-路由键
        /// </summary>
        private readonly string _routingKeyRegister = "queue.register";

        /// <summary>
        /// 心跳-路由键
        /// </summary>
        private readonly string _routingKeyHeart = "queue.heart";

        /// <summary>
        /// 取消信号
        /// </summary>
        private readonly CancellationTokenSource _cts = new();

        /// <summary>
        /// 回调函数映射器
        /// </summary>
        private readonly ConcurrentDictionary<string, TaskCompletionSource<string>> _callbackMapper = new();

        private bool _connectionState;
        private bool _sendChannelState;
        private bool _listenChannelState;

        /// <summary>
        /// 连接状态
        /// </summary>
        public bool ConnectionState
        {
            get { return _connectionState; }
            set 
            {
                if (_connectionState == value)
                {
                    return;
                }

                _connectionState = value;
                if (_connectionState)
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 连接已打开");
                }
                else
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 连接已关闭");
                }
            }
        }

        /// <summary>
        /// 发送通道状态
        /// </summary>
        public bool SendChannelState
        {
            get { return _sendChannelState; }
            set 
            {
                if (_sendChannelState == value)
                {
                    return;
                }

                _sendChannelState = value;
                if (_sendChannelState)
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 发送通道已打开");
                }
                else
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 发送通道已关闭");
                }
            }
        }

        /// <summary>
        /// 接收通道状态
        /// </summary>
        public bool ListenChannelState
        {
            get { return _listenChannelState; }
            set 
            {
                if (_listenChannelState == value)
                {
                    return;
                }

                _listenChannelState = value;
                if (_listenChannelState)
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 接收通道已打开");
                }
                else
                {
                    Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff}: 接收通道已关闭");
                }
            }
        }

        /// <summary>
        /// 定义私有构造函数,使外界不能创建该类实例 
        /// </summary>
        private RabbitMQRpcClientHandler()
        {
            // 创建连接工厂
            _factory = new ConnectionFactory()
            {
                HostName = _defaultRabbitMQHostName,//MQ服务器地址
                Port = _defaultRabbitMQPort,//MQ服务端口号
                UserName = _defaultRabbitMQUserName,//账号
                Password = _defaultRabbitMQPassword,//密码
                VirtualHost = _defaultRabbitMQVirtualHost,
                RequestedHeartbeat = TimeSpan.FromSeconds(2),
                AutomaticRecoveryEnabled = true,//自动重连
                TopologyRecoveryEnabled = true,//拓扑重连
                NetworkRecoveryInterval = TimeSpan.FromSeconds(10)
            };
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static RabbitMQRpcClientHan
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值