RabbitMQ消息发送确认

RabbitMQ生产者确保消息发送成功,可用于消息最终一致性解决方案,消息确认有两种方式:事务和Confirm

1、事务方式实现保证消息正确发送出去(到达消息服务)

说明:事务会降低消息的吞吐量

static void Main(string[] args)
{
    //事务方式
    TransactionMode();
    //消息确认方式
    //ConfirmModel();
    Console.ReadLine();
}
/// <summary>
/// 使用事务方式确保数据正确到达消息服务端
/// </summary>
static void TransactionMode()
{
    var sign = true;
    ConnectionFactory factory = new ConnectionFactory { HostName = "127.0.0.1", UserName = "guest", Password = "guest", VirtualHost = "/" };
    using (IConnection conn = factory.CreateConnection())
    {
        using (IModel im = conn.CreateModel())
        {
            try
            {
                im.TxSelect(); //用于将当前channel设置成transaction事务模式
                im.ExchangeDeclare("my-exchange", ExchangeType.Direct);
                im.QueueDeclare("my-queue", true, false, false, null);
                im.QueueBind("my-queue", "my-exchange", "", null);
                var properties = im.CreateBasicProperties();
                properties.DeliveryMode = 2;
                Console.Write("输入发送的内容:");
                var msg = Console.ReadLine();
                if (msg == "quit")
                    sign = false;
                //for (var i = 1; i <= 100; i++)
                //{
                //    byte[] message = Encoding.UTF8.GetBytes("发送消息:" + i);
                //    im.BasicPublish("my-exchange", ExchangeType.Direct, properties, message);
                //    Console.WriteLine("发送消息:" + i);
                //}
                byte[] message = Encoding.UTF8.GetBytes("发送消息:" + msg);
                im.BasicPublish("my-exchange", ExchangeType.Direct, properties, message);
                im.TxCommit();//txCommit用于提交事务
            }
            catch (Exception ex)
            {
                im.TxRollback();
            }
        }
    }
}

2、Comfirm方式

static void Main(string[] args)
{
    //事务方式
    //TransactionMode();
    //消息确认方式
    ConfirmModel();
    Console.ReadLine();
}
static void ConfirmModel()
{
    ConnectionFactory factory = new ConnectionFactory { HostName = "127.0.0.1", UserName = "guest", Password = "guest", VirtualHost = "/" };
    using (IConnection conn = factory.CreateConnection())
    {
        using (IModel channel = conn.CreateModel())
        {
            channel.ExchangeDeclare("my-exchange", ExchangeType.Fanout);
            channel.QueueDeclare("my-queue", true, false, false, null);
            channel.QueueBind("my-queue", "my-exchange", "", null);
            var properties = channel.CreateBasicProperties();
            properties.DeliveryMode = 2;
            byte[] message = Encoding.UTF8.GetBytes("发送消息!");
            //方式1:普通confirm 
            //NormalConfirm(channel, properties, message);
            //方式2:批量confirm
            //BatchConfirm(channel, properties, message);
            //方式3:异步确认Ack
            ListenerConfirm(channel, properties, message);
        }
    }
}

 方式1:普通confirm

/// <summary>
/// 方式1:普通confirm模式
/// 每发送一条消息后,调用waitForConfirms()方法,等待服务器端confirm。实际上是一种串行confirm了。
/// </summary>
/// <param name="channel"></param>
/// <param name="properties"></param>
/// <param name="message"></param>
static void NormalConfirm(IModel channel, IBasicProperties properties, byte[] message)
{
    channel.ConfirmSelect();
    channel.BasicPublish("my-exchange", ExchangeType.Fanout, properties, message);
    if (!channel.WaitForConfirms())
    {
        Console.WriteLine("send message failed.");
    }
    Console.WriteLine("send message success.");
}

方式2:批量confirm

/// <summary>
/// 方式2:批量confirm模式
/// 每发送一批消息后,调用waitForConfirms()方法,等待服务器端confirm。
/// </summary>
/// <param name="channel"></param>
/// <param name="properties"></param>
/// <param name="message"></param>
static void BatchConfirm(IModel channel, IBasicProperties properties, byte[] message)
{
    channel.ConfirmSelect();
    for (int i = 0; i < 10; i++)
    {
        channel.BasicPublish("my-exchange", ExchangeType.Fanout, properties, message);
    }
    if (!channel.WaitForConfirms())
    {
        Console.WriteLine("send message failed.");
    }
    Console.WriteLine("send message success.");
    channel.Close();
}

方式3:异步回调方式确认Ack 

/// <summary>
/// 使用异步回调方式监听消息是否正确送达
/// </summary>
/// <param name="channel"></param>
/// <param name="properties"></param>
/// <param name="message"></param>
static void ListenerConfirm(IModel channel, IBasicProperties properties, byte[] message)
{
    channel.ConfirmSelect();//开启消息确认模式
    /*-------------Return机制:不可达的消息消息监听--------------*/
    //这个事件就是用来监听我们一些不可达的消息的内容的:比如某些情况下,如果我们在发送消息时,当前的exchange不存在或者指定的routingkey路由不到,这个时候如果要监听这种不可达的消息,就要使用 return
    EventHandler<BasicReturnEventArgs> evreturn = new EventHandler<BasicReturnEventArgs>((o, basic) =>
    {
        var rc = basic.ReplyCode; //消息失败的code
        var rt = basic.ReplyText; //描述返回原因的文本。
        var msg = Encoding.UTF8.GetString(basic.Body.Span); //失败消息的内容
        //在这里我们可能要对这条不可达消息做处理,比如是否重发这条不可达的消息呀,或者这条消息发送到其他的路由中等等
        //System.IO.File.AppendAllText("d:/return.txt", "调用了Return;ReplyCode:" + rc + ";ReplyText:" + rt + ";Body:" + msg);
        Console.WriteLine("send message failed,不可达的消息消息监听.");
    });
    channel.BasicReturn += evreturn;
    //消息发送成功的时候进入到这个事件:即RabbitMq服务器告诉生产者,我已经成功收到了消息
    EventHandler<BasicAckEventArgs> BasicAcks = new EventHandler<BasicAckEventArgs>((o, basic) =>
    {
        Console.WriteLine("send message success,Acks.");
        //System.IO.File.AppendAllText("d:/ack.txt", "\r\n调用了ack;DeliveryTag:" + basic.DeliveryTag.ToString() + ";Multiple:" + basic.Multiple.ToString() + "时间:" + DateTime.Now.ToString());
    });
    //消息发送失败的时候进入到这个事件:即RabbitMq服务器告诉生产者,你发送的这条消息我没有成功的投递到Queue中,或者说我没有收到这条消息。
    EventHandler<BasicNackEventArgs> BasicNacks = new EventHandler<BasicNackEventArgs>((o, basic) =>
    {
        //MQ服务器出现了异常,可能会出现Nack的情况
        Console.WriteLine("send message fail,Nacks.");
        //System.IO.File.AppendAllText("d:/nack.txt", "\r\n调用了Nacks;DeliveryTag:" + basic.DeliveryTag.ToString() + ";Multiple:" + basic.Multiple.ToString() + "时间:" + DateTime.Now.ToString());
    });
    channel.BasicAcks += BasicAcks;
    channel.BasicNacks += BasicNacks;
    channel.BasicPublish("my-exchange", ExchangeType.Fanout, properties, message);
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值