代码改变世界

RabbitQueue相关

2019-10-30 10:37  .net小跟班(杜)  阅读(192)  评论(0编辑  收藏  举报
private static IConnection Connection = null;
        /// <summary>
        /// 发送消息到指定队列
        /// </summary>
        /// <param name="queueName">队列名称, 如果没有则自动创建</param>
        /// <param name="obj">消息主体,建议使用Json</param>
        /// <param name="TTL">过期时间,到时会转换到不带.TTL的队列中,在那个队列中消费处理</param>
        public static void Send(RabbitQueue queueName, string Suffix, object obj, int TTL = 0)
        {
            try
            {
                Task.Run(delegate
                {
                    Config config = new Rabbit.Config();
                    //从队列枚举的描述中获取队列名,并附加队列子名称
                    string QueueName_Receive = config.Rabbit_QueueNameFixed + queueName.GetDesc() + (string.IsNullOrEmpty(Suffix) ? string.Empty : "." + Suffix);

                    //判断当前消息是否要延时,如果延时则附加.TTL作为暂存队列
                    string QueueName = QueueName_Receive + (TTL == 0 ? string.Empty : ".TTL");
                    try
                    {
                        //将客户端和连接对象作为全局变量,只有在关闭了之后再重新连接,能有效的提高入站效率
                        if (Connection == null || !Connection.IsOpen) { Connection = Config.InitFactory().CreateConnection(); }

                        using (var channel = Connection.CreateModel())
                        {

                            //创建一个队列  队列名称
                            bool durable = true;      //设置队列持久化 服务器重启时,该队列依然能够存活 如果使用Exchange转发器,则需要转发器也是支持本地化的
                            bool exclusive = false;   //是否为当前连接的专用队列,在连接断开后,会自动删除该队列,生产环境中应该不会用到
                            bool autodelete = false;  //当没有任何消费者使用时,自动删除该队列, 否,其实无所谓,因为一般下次添加队列或者处理队列的时候都会先创建队列

                            #region //设置消息的基本参数 持久化等
                            //设置性能
                            var properties = channel.CreateBasicProperties();
                            //设置消息持久化
                            //需要注意的是,将消息设置为持久化并不能完全保证消息不丢失。
                            //虽然他告诉RabbitMQ将消息保存到磁盘上,但是在RabbitMQ接收到消息和将其保存到磁盘上这之间仍然有一个小的时间窗口。 
                            //RabbitMQ 可能只是将消息保存到了缓存中,并没有将其写入到磁盘上。持久化是不能够一定保证的,但是对于一个简单任务队列来说已经足够。
                            //如果需要消息队列持久化的强保证,可以使用publisher confirms
                            properties.Persistent = true;
                            //1:不持久化 2:持久化 这里指的是消息的持久化,配合channel(durable=true),queue(durable)可以实现,即使服务器宕机,消息仍然保留
                            properties.DeliveryMode = 2;
                            #endregion

                            if (TTL == 0)  //如果不需要设置过期 则直接加入队列
                            {
                                channel.QueueDeclare(QueueName_Receive, durable, exclusive, autodelete, null);
                            }
                            else
                            {
                                string ExchangeName = QueueName + ".Exchange"; //转发器名称
                                string RouteKey = QueueName + ".RouteKey"; //转向路由名称

                                //如果要实现过期.. 实现原理是将消息设置过期时间之后放在队列中..而此队列一直没有消费者会去消费.. 让消息过期..变成死信(Dead Letter)
                                //消息会根据队列上配置的转发器Exchange 来转发消息.. 消息会被推送到其他绑定了此转发器的队列上.. 那个队列有实时消费者..这样就形成了消息的延时处理..延时的时长是灵活设置的


                                //需要设置过期..要创建对应的过期结构.
                                //将消息加入到一个会过期的队列中..本方法中将原队列名后缀加上.TTL.. 实际转发消息队列为枚举获取到的队列名,方便后期消费处理
                                //可以在队列上设置过期时间,参数名:x-message-ttl 单位毫秒 在下方的键值对Dic中设置
                                //也可以在消息上设置过期时间..更下方的properties 的 Expiration 属性..单位也是毫秒 在消息上设置过期时间更加灵活.. 消息会比较多个过期时间取最小值


                                //此处需要注意的是
                                Dictionary<string, object> dic = new Dictionary<string, object>();
                                dic.Add("x-dead-letter-exchange", ExchangeName);//过期消息转发器
                                dic.Add("x-dead-letter-routing-key", RouteKey);//过期消息转向路由相匹配routingkey

                                //创建ExChange转发器
                                //设置转发器也是可以本地化  不自动删除的
                                channel.ExchangeDeclare(exchange: ExchangeName, type: "direct", durable: true, autoDelete: false, arguments: null);
                                //声明虚假队列 此队列没有消费端 会按消息上设置的时间过期
                                channel.QueueDeclare(QueueName, durable, exclusive, autodelete, dic);
                                //通过当前 Channel 绑定QueryName Exchange  和 routingKey
                                channel.QueueBind(QueueName, ExchangeName, RouteKey);

                                //声明真实的队列
                                channel.QueueDeclare(QueueName_Receive, durable, exclusive, autodelete, null);
                                channel.QueueBind(QueueName_Receive, ExchangeName, RouteKey);


                                //设置消息的过期时间
                                properties.Expiration = TTL.ToString();
                            }
                            //内容
                            channel.BasicPublish("", QueueName, false, properties, obj.ToJson().ToBytes(Encoding.UTF8));
                        }
                    }
                    catch (System.Exception ex)
                    {
                        Console.WriteLine(ex);
                        Console.WriteLine("{0} - {1} - {2} - {3}", DateTime.Now.Format_yyyyMMddHHmmssfff(), QueueName, ex.Message, obj.ToJson());
                    }
                });
            }
            catch (System.Exception ex)
            {
                System.Console.WriteLine(ex);
            }

        }