如何從釋出者和消費者方面使用rabbitmq進行恢復

風靈使發表於2018-07-21

建立

使用官方的RabbitMQ docker容器並通過執行啟動佇列

docker run -d --hostname my-rabbit --name some-rabbit -p 808015672 -p 56725672 rabbitmq:3-management

在釋出者擁有佇列的那一刻,通過啟動它,將建立佇列並使用他們自己的路由鍵定義兩個主題。

釋出者

using System;
using RabbitMQ.Client;
using System.Text;
using System.Threading;

namespace publisher
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rnd = new Random();
            Console.WriteLine("Starting publisher!");
            var factory = setupConnection();

            using(var connection = factory.CreateConnection())
            using(var channel = connection.CreateModel()){ 
                //佇列
                //在宣告佇列時,請記住考慮佇列應具有的永續性以及是否應該是排他性佇列(Exclusive Queue)。
                // channel.QueueDeclare(queue: "pingpong", 
                //                      durable: false,
                //                      exclusive: false,
                //                      autoDelete: false,
                //                      arguments: null);

                channel.QueueDeclare(queue: "pingpongA",
                                     durable: true,
                                     exclusive: false,
                                     autoDelete: false,
                                     arguments: null);

                channel.QueueDeclare(queue: "pingpongB",
                                     durable: false,
                                     exclusive: false,
                                     autoDelete: false,
                                     arguments: null);

                //Topic
                channel.ExchangeDeclare(exchange: "pingpong",
                                        type: "topic");

                //使用Topic繫結特定佇列並定義路由鍵
                channel.QueueBind(queue: "pingpongA",
                                  exchange: "pingpong",
                                  routingKey: "topicA");

                channel.QueueBind(queue: "pingpongB",
                                  exchange: "pingpong",
                                  routingKey: "topicB");

                while (true)
                {
                    string messageTopicA = Guid.NewGuid() + ", Hello TopicA!, " + DateTime.Now;
                    var bodyTopicA = Encoding.UTF8.GetBytes(messageTopicA);
                    string messageTopicB = Guid.NewGuid() + ", Hello TopicB!, " + DateTime.Now;
                    var bodyTopicB = Encoding.UTF8.GetBytes(messageTopicB);
                    try
                    { 
                        //佇列
                        //對於每個佇列,請考慮使用路由鍵來處理請求/響應模式。 這將使用相同的topic,但在該topic上建立特定的路由。
                        // channel.BasicPublish(exchange: "",
                        //             routingKey: "sent",
                        //             basicProperties: null,
                        //             body: body);
                        //考慮做釋出者確認,這將引入開銷,因為需要維護事務,有關詳細資訊,請參閱https://www.rabbitmq.com/confirms.html


                        //Topic
                        channel.BasicPublish(exchange: "pingpong",
                                        routingKey: "topicA",
                                        basicProperties: null,
                                        body: bodyTopicA);

                        channel.BasicPublish(exchange: "pingpong",
                                        routingKey: "topicB",
                                        basicProperties: null,
                                        body: bodyTopicB);

                        //生成一些隨機行為
                        Console.WriteLine(" [x] Sent {0}", messageTopicA);
                        Console.WriteLine(" [y] Sent {0}", messageTopicB);
                        Thread.Sleep(rnd.Next(2000, 6000));
                    } 
                    //捕獲生成的異常,這是在網路或rabbitmq更改下丟擲的。 該異常包含一條訊息,有時可以解釋丟擲的異常型別。
                    catch (RabbitMQ.Client.Exceptions.AlreadyClosedException)
                    {
                        Console.WriteLine("Connection is down, trying to reconnect.");
                    }

                }
            }

        }

        static ConnectionFactory setupConnection()
        {
            var factory = new ConnectionFactory();
            factory.HostName = "localhost";

            //設定恢復選項
            factory.AutomaticRecoveryEnabled = true;
            factory.TopologyRecoveryEnabled = true;

            //來自標準文件
            factory.RequestedHeartbeat = 60;

            //隨機化連線間隔,因此多個連線不會嘗試同時重新連線。
            Random rnd = new Random();
            factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(rnd.Next(15, 45));


            return factory;
        }
    }
}

消費者

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace consumer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Starting Consumer!");
            var factory = setupConnection();

            using (var connection = factory.CreateConnection())
            using (var channel = connection.CreateModel())
            {

                //佇列
                //宣告確定佇列存在,考慮釋出者或消費者是否應該建立佇列
                // channel.QueueDeclare(queue: "pingpongA",
                //                      durable: true,
                //                      exclusive: false,
                //                      autoDelete: false,
                //                      arguments: null);

                // channel.QueueDeclare(queue: "pingpongB",
                //                      durable: false,
                //                      exclusive: false,
                //                      autoDelete: false,
                //                      arguments: null);

                // var consumer = new EventingBasicConsumer(channel);
                // consumer.Received += (model, ea) =>
                // {
                //     var body = ea.Body;
                //     var message = Encoding.UTF8.GetString(body);
                //     Console.WriteLine(" [x] Received {0}", message);
                // };

               //記住考慮自動確認是否應該為真,首選是完全處理請求然後確認。
                // channel.BasicConsume(queue: "pingpong",
                //                      autoAck: true,
                //                      consumer: consumer);

                //Topic
                channel.ExchangeDeclare(exchange: "pingpong", type: "topic");

                //使用Topic繫結特定佇列並定義路由鍵
                // channel.QueueBind(queue: "pingpongA",
                //                   exchange: "pingpong",
                //                   routingKey: "topicA");

                // channel.QueueBind(queue: "pingpongB",
                //                   exchange: "pingpong",
                //                   routingKey: "topicB");

                //生成消費者
                var consumer = new EventingBasicConsumer(channel);
                consumer.Received += (model, ea) =>
                {
                    var body = ea.Body;
                    var message = Encoding.UTF8.GetString(body);
                    var routingKey = ea.RoutingKey;
                    Console.WriteLine(" [x] Received '{0}':'{1}'",
                                    routingKey,
                                    message);
                    channel.BasicAck(ea.DeliveryTag, false);
                };

                //啟動兩個不同佇列的消費者
                channel.BasicConsume(queue: "pingpongA",
                                 autoAck: false,
                                 consumer: consumer);

                channel.BasicConsume(queue: "pingpongB",
                                 autoAck: false,
                                 consumer: consumer);
                Console.ReadLine();
            }
        }

        static ConnectionFactory setupConnection()
        {
            var factory = new ConnectionFactory();
            factory.HostName = "localhost";

            //AutomaticRecoveryEnabled  斷線重連,也就是如果當前的連線斷開了,將會嘗試重連

            //TopologyRecoveryEnabled 重連後恢復當前的工作程式,比如channel、queue、釋出的訊息進度等 //設定重新宣告交換器,佇列等資訊。
            //設定恢復選項
            factory.AutomaticRecoveryEnabled = true;
            factory.TopologyRecoveryEnabled = true;

            //來自標準文件
            factory.RequestedHeartbeat = 60;

            //隨機化連線間隔,因此多個連線不會嘗試同時重新連線。
            Random rnd = new Random();
            //設定每15-45s ,重試一次
            factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(rnd.Next(15, 45));

            return factory;
        }
    }
}

相關文章