RabbitMQ心跳检测与掉线重连

1、RabbitMQListener,自定义消息监听器

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MQ_Receive
{
    public class RabbitMQListener
    {
        private ConnectionFactory _factory;
        private IConnection _con;
        private IModel _channel;
        private EventingBasicConsumer _consumer;

        private string _rabbitMQUri;
        private string _exchangeType;
        private string _exchangeName;
        private string _queueName;
        private string _routeKey;
        private Func<string, bool> _messageHandler;

        /// <summary>
        /// RabbitMQ消息监听器
        /// </summary>
        /// <param name="rabbitMQUri">例子,amqp://guest:guest@localhost:5672/</param>
        /// <param name="exchangeName">消息交换机</param>
        /// <param name="exchangeType">交换机类型,如 ExchangeType.Direct</param>
        /// <param name="queueName">要监听的队列</param>
        /// <param name="routeKey"></param>
        public RabbitMQListener(string rabbitMQUri, string exchangeName, string exchangeType, string queueName, string routeKey = "")
        {
            this._rabbitMQUri = rabbitMQUri;
            this._exchangeName = exchangeName;
            this._exchangeType = exchangeType;
            this._queueName = queueName;
            this._routeKey = routeKey;
        }

        /// <summary>
        /// 创建连接
        /// </summary>
        private void CreateConnection()
        {
            _factory = new ConnectionFactory();
            _factory.Uri = new Uri(_rabbitMQUri);
            _factory.RequestedHeartbeat = 20;
            _factory.AutomaticRecoveryEnabled = true;
            _factory.TopologyRecoveryEnabled = true;
            _factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);

            _con = _factory.CreateConnection();
            _con.ConnectionShutdown += con_ConnectionShutdown;
        }

        /// <summary>
        /// 创建信道
        /// </summary>
        private void CreateChannel()
        {
            _channel = _con.CreateModel();
            _channel.ExchangeDeclare(_exchangeName, ExchangeType.Direct, true, false, null);
            _channel.QueueDeclare(_queueName, true, false, false, null); //创建一个消息队列,用来存储消息
            _channel.QueueBind(_queueName, _exchangeName, _routeKey, null);
            _channel.BasicQos(0, 3, true); //在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息
        }

        /// <summary>
        /// 监听队列消息
        /// </summary>
        /// <param name="messageHandler"></param>
        public void MessageListen(Func<string, bool> messageHandler)
        {
            try
            {
                this.CreateConnection();
                this.CreateChannel();

                _consumer = new EventingBasicConsumer(_channel); //基于事件的消息推送方式
                _consumer.Received += (_sender, _e) =>
                {
                    string msg = Encoding.UTF8.GetString(_e.Body);
                    if (messageHandler != null)
                    {
                        this._messageHandler = messageHandler;
                        var isOk = this._messageHandler(msg);
                        if (isOk)
                        {
                            _channel.BasicAck(_e.DeliveryTag, false);
                        }
                    }
                };

                _channel.BasicConsume(_queueName, false, _consumer); //手动确认
            }
            catch (RabbitMQ.Client.Exceptions.BrokerUnreachableException e)
            {
                throw e;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 掉线重新连接并监听队列消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void con_ConnectionShutdown(object sender, ShutdownEventArgs e)
        {
            ReMessageListen();
        }

        public void ReMessageListen()
        {
            try
            {
                //清除连接及频道
                Cleanup();

                var mres = new ManualResetEventSlim(false); // state is initially false
                while (!mres.Wait(3000)) // loop until state is true, checking every 3s
                {
                    try
                    {
                        MessageListen(_messageHandler);
                        mres.Set(); // state set to true - breaks out of loop
                    }
                    catch (Exception ex)
                    {
                        //LogHandler.WriteLog("RabbitMQ尝试连接RabbitMQ服务器出现错误:" + ex.Message, ex);
                    }
                }
            }
            catch (Exception ex)
            {
                //LogHandler.WriteLog("RabbitMQ尝试重新连接RabbitMQ服务器出现错误:" + ex.Message, ex);
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        private void Cleanup()
        {
            try
            {
                if (_channel != null && _channel.IsOpen)
                {
                    try
                    {
                        _channel.Close();
                    }
                    catch (Exception ex)
                    {
                        //LogHandler.WriteLog("RabbitMQ重新连接,正在尝试关闭之前的Channel[发送],但遇到错误", ex);
                    }
                    _channel = null;
                }

                if (_con != null && _con.IsOpen)
                {
                    try
                    {
                        _con.Close();
                    }
                    catch (Exception ex)
                    {
                        //LogHandler.WriteLog("RabbitMQ重新连接,正在尝试关闭之前的连接,但遇到错误", ex);
                    }
                    _con = null;
                }
            }
            catch (IOException ex)
            {
                throw ex;
            }
        }
    }
}

2、调用代码

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace MQ_Receive
{
    public partial class Form1 : Form
    {
        private delegate void ChangeText(string text);
        private readonly ChangeText _changeText;

        private static string rabbitHostUri = "amqp://guest:guest@localhost:5672/";
        private static string exchangeName = "order-exchange";
        private static string queueName = "order-message-test-queue";
        private static string routeKey = "order-message-routeKey";
        private static readonly object lockObj = new object();

        private static RabbitMQListener _listener;
        public static RabbitMQListener RabbitMQListener
        {
            get
            {
                if (_listener == null)
                {
                    lock (lockObj)
                    {
                        if (_listener == null)
                        {
                            _listener = new RabbitMQListener(rabbitHostUri, exchangeName, ExchangeType.Direct, queueName, routeKey);
                        }
                    }
                }

                return _listener;
            }
        }
        private Func<string, bool> MessageHandler
        {
            get {
                     return (msg) =>
                     {
                         this.label1.Invoke(_changeText, new object[1] { msg });
                         return true;
                     };
                }
        }

        public Form1()
        {
            InitializeComponent();
            this.label1.Text = "";
            this._changeText = SetText;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            RabbitMQListener.MessageListen(MessageHandler);
        }

        private void SetText(string text)
        {
            this.label1.Text += text + "\n";
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/huangzelin/p/10908072.html