菜鸟使用RabbitMQ消息队列感触
public class MQConnection
{
private static IConnection Connection;
配置:
public static IConnection GetConnection()
{
if (Connection == null)
{
var factory = new ConnectionFactory()
{
HostName = BasicConfig.MQHostName,
UserName = BasicConfig.MQUserName,
Password = BasicConfig.MQPassword,
VirtualHost= BasicConfig.MQVirtualHost,
RequestedHeartbeat = new TimeSpan(60),//指定连接的心跳间隔时间,用于检测连接是否存活
AutomaticRecoveryEnabled = true, //要启用自动连接恢复
TopologyRecoveryEnabled=true,//指定是否启用拓扑恢复功能
};
//创建连接
Connection = factory.CreateConnection();
return Connection;
}
return Connection;
}
}
生产消息:
public static ResultInfo Dlx_Publish(string strBody)
{
ResultInfo res = new ResultInfo();
try
{
using (var channel = MQConnection.GetConnection().CreateModel())
{
// 声明死信交换机
channel.ExchangeDeclare("dlx_exchange", ExchangeType.Direct,true);
// 声明死信队列
channel.QueueDeclare("dlx_info_queue", true, false, false, null);
// 绑定死信队列到死信交换机(假设使用固定的路由键)
channel.QueueBind("dlx_info_queue", "dlx_exchange", "dlx_routing_key");
// 声明普通队列,并设置死信交换机和路由键
var queueArgs = new Dictionary<string, object>
{
{ "x-dead-letter-exchange", "dlx_exchange" },
{ "x-dead-letter-routing-key", "dlx_routing_key" }
};
var MQExchange = BasicConfig.MQExchange;
// 声明Fanout交换机
channel.ExchangeDeclare(MQExchange, BasicConfig.MQExchangeType, true, false, queueArgs);
//开启ACK确认
channel.ConfirmSelect();
// 设置消息的expiration属性,这里设置为5秒
var properties = channel.CreateBasicProperties();
properties.Expiration = "5000"; // 毫秒为单位
try
{
// 定义要发送的消息
var body = Encoding.UTF8.GetBytes(strBody);
channel.BasicAcks += (sender, ea) =>
{
res.Success = true;
res.Message = $"消息发送成功";
};
channel.BasicNacks += (sender, ea) =>
{
res.Success = false;
res.Message = $"消息发送失败";
};
// 发送消息到Fanout交换机
channel.BasicPublish(exchange: MQExchange, routingKey: "", basicProperties: properties, body: body);
}
catch (Exception ex)
{
res.Success = false;
res.Message = $"消息发生异常:{ex.Message}-{ex.StackTrace}-{ex.InnerException?.Message}";
}
}
}
catch (Exception ex)
{
res.Success = false;
res.Message = $"消息发生异常:{ex.Message}-{ex.StackTrace}-{ex.InnerException?.Message}";
}
return res;
}
消费消息:
///
/// 此方法直接读取队列 ,不做队列声明
///
public static void ReceivedQueueInfor()
{
try
{
string strQueue = BasicConfig.MQQueue;
using (var channel = MQConnection.GetConnection().CreateModel())
{
if (QueueExists(channel, strQueue))
{
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var msg = Encoding.UTF8.GetString(body);
// 使用Polly实现重试策略
var policyRetryCount = 0;
var retryPolicy = Policy.Handle
.Retry(3, (exception, retryCount) => // 最多重试3次
{
Console.WriteLine($"Exception in processing message. Retrying: {retryCount}");
policyRetryCount = retryCount;
Thread.Sleep(1000);
});
retryPolicy.Execute(() =>
{
var result = ProcessMessage(msg);
if (result)
{
Console.WriteLine($"消息消费成功");
channel.BasicAck(ea.DeliveryTag, false);
}
else
{
Console.WriteLine($"消息消费失败");
if (policyRetryCount == 3)
{
// 消息处理失败,重新入队
channel.BasicNack(ea.DeliveryTag, false, true);
Console.WriteLine("消息重试处理 3次失败,重新入队");
}
throw new Exception("processing failure");
}
});
};
channel.BasicConsume(strQueue, false, consumer);
}
else
{
Console.WriteLine("消息队列不存在!");
}
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.WriteLine($"消息消费发生异常:{ex.Message}-{ex.StackTrace}-{ex.InnerException?.Message}");
}
}
/// <summary>
/// 此方法读取死信队列
/// </summary>
public static void Dlx_ReceivedMQ()
{
using (var channel = MQConnection.GetConnection().CreateModel())
{
// 这里的queueName应该替换为你想要消费的队列的名称
string queueName = BasicConfig.DlxMQQueue;
if (QueueExists(channel, queueName))
{
// 声明一个消费者
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = System.Text.Encoding.UTF8.GetString(body);
var res = Dlx_Publish(message);
if (res.Success)
{
// 处理完消息后应答
channel.BasicAck(ea.DeliveryTag, false);
LogHelper.Write($"{DateTime.Now}-Received Message: {message}");
Console.WriteLine("Received Message: {0}", message.Length > 100 ? message.Substring(0, 100) : message);
}
else {
// 消息处理失败,重新入队
channel.BasicNack(ea.DeliveryTag, false, true);
}
};
Console.WriteLine("start processing messages!");
// 开始消费消息
channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer);
}
else
{
Console.WriteLine("消息队列不存在!");
}
Console.ReadLine();
}
}
/// <summary>
/// 判断队列是否存在
/// </summary>
/// <param name="channel"></param>
/// <param name="queueName"></param>
/// <returns></returns>
private static bool QueueExists(IModel channel, string queueName)
{
// 尝试获取声明队列,如果队列不存在,会抛出异常
try
{
var queue = channel.QueueDeclarePassive(queueName);
// 如果声明成功,队列存在
return true;
}
catch (Exception ex)
{
LogHelper.Write(ex);
// 队列不存在
return false;
}
}