.net core 下使用 RabbitMQ 死信队列 (二)
消息到死信队列的三种情况
- 消息被拒(basic.reject or basic.nack)并且没有重新入队(requeue=false);
- 当前队列中的消息数量已经超过最大长度。
- 消息在队列中过期,即当前消息在队列中的存活时间已经超过了预先设置的TTL(Time To Live)时间;
以下是代码实现
发送到消息 其实就是 正常队列 挂 死信队列
1 /// <summary> 2 ///发送消息(死信队列) 3 /// </summary> 4 /// <param name="msg"></param> 5 public void DLXSend(string msg) 6 { 7 //正常队列 8 var exchangeNormal = "normal.exchange"; 9 var routeNormal = "normal.routekey"; 10 var queueNormal = "normal.queue"; 11 //死信队列 12 var exchangeDLX = "dlx.exchange"; 13 var routeDLX = "dlx.route"; 14 var queueDLX = "dlx.queue"; 15 16 this.Connection(); 17 IModel channel = this._connection.CreateModel(); 18 //死信队列交换机 19 channel.ExchangeDeclare(exchangeDLX, ExchangeType.Fanout, true, false, null); 20 //死信队列 21 channel.QueueDeclare(queueDLX, true, false, false); 22 23 channel.QueueBind(queueDLX, exchangeDLX, routeDLX); 24 25 //正常队列交换机 26 channel.ExchangeDeclare(exchangeNormal, ExchangeType.Fanout, true, false); 27 //正常队列 28 channel.QueueDeclare(queueNormal, true, false, false, new Dictionary<string, object> { 29 { "x-dead-letter-exchange",exchangeDLX}, //设置当前队列交换机的DLX 30 { "x-dead-letter-routing-key",routeDLX}, //设置DLX的路由key,DLX会根据该值去找到死信消息存放的队列 31 { "x-message-ttl",30000} //设置消息的存活时间,即过期时间 30秒 32 }); 33 //绑定正常交换机 34 channel.QueueBind(queueNormal, exchangeNormal, routeNormal); 35 36 var properties = channel.CreateBasicProperties(); 37 properties.Persistent = true; 38 //发布消息 39 channel.BasicPublish(exchange: exchangeNormal, 40 routingKey: routeNormal, 41 basicProperties: properties, 42 body: Encoding.UTF8.GetBytes("hello rabbitmq message")); 43 44 }
消费死信队列的消息
1 /// <summary> 2 /// 接收死信队列 3 /// </summary> 4 public void ReceiveDLX(Func<string,bool>func) 5 { 6 //建立连接 7 Connection(); 8 //建立信道 9 IModel channel = this._connection.CreateModel(); 10 //死信队列交换机 11 channel.ExchangeDeclare("dlx.exchange", ExchangeType.Fanout, true, false, null); 12 //死信队列 13 channel.QueueDeclare("dlx.queue", true, false, false); 14 15 channel.QueueBind("dlx.queue", "dlx.exchange", "dlx.route", null); 16 17 var consumer = new EventingBasicConsumer(channel); 18 consumer.Received += (object? sender, BasicDeliverEventArgs e) => 19 { 20 byte[] bytes = e.Body.ToArray(); 21 string recevieMessage = Encoding.UTF8.GetString(bytes); 22 if (func(recevieMessage)) 23 { 24 //这里是收到消息后 手动确认接收到消息也就是手动ACK 25 channel.BasicAck(e.DeliveryTag, false); 26 } 27 else 28 { 29 //拒收,是接收端在收到消息的时候响应给RabbitMQ服务的一种命令, 30 //告诉服务器不应该由我处理,或者拒绝处理,扔掉。接收端在发送reject命令的时候可以选择是 31 //否要重新放回queue中。 32 //如果没有其他接收者监控这个queue的话,要注意一直无限循环发送的危险。 33 channel.BasicReject(deliveryTag: e.DeliveryTag, requeue: true);//放回队列--重新包装信息,放入其他队列 34 } 35 }; 36 // 3、消费消息 37 channel.BasicQos(0, 1, false); // Qos(防止多个消费者,能力不一致,导致的系统质量问题。 每一次一个消费者只成功消费一个) 38 channel.BasicConsume("dlx.queue", false, consumer); 39 }
测试结果 正常队列 1条信息 30秒后 进入到死信队列中
消息已经进入到死信队列中了
死信队列消息被消费了