go rabbitmq 延时队列代码实现 (延时插件 x-delayed-message)

1.插件和 包说明

rabbitmq延时队列有 x-delayed-message 插件,我上一篇有如何安装延时插件说明

另使用的包是 github.com/streadway/amqp  go get 一下即可

2.封装生产者代码

建一个包,用于封装生产者的一些操作

package mq

import (
	"errors"

	"github.com/streadway/amqp"
)

type DelayedProducter struct {
	Conn    *amqp.Connection
	Channel *amqp.Channel
	// 队列名称
	QueueName string
	// 交换机
	Exchange string
	// routing Key
	RoutingKey string
	//MQ链接字符串
	Mqurl string
}

func (dp *DelayedProducter) InitDelayedProducter() error {

	dp.Mqurl = "amqp://xxxooo:123456@127.0.0.1:5672/"
	dp.Exchange = "delayed-exchange" //交换机名
	dp.RoutingKey = "delay-key"      //路由key
	dp.QueueName = "delayed-queue"   //队列名称
	//创建连接
	var err error
	dp.Conn, err = amqp.Dial(dp.Mqurl)
	if err != nil {
		return errors.New("连接失败:" + err.Error())
	}

	//创建通道
	dp.Channel, err = dp.Conn.Channel()
	if err != nil {
		dp.Conn.Close() //关闭连接
		return errors.New("连接失败:" + err.Error())
	}

	//声明延迟交换机
	err = dp.Channel.ExchangeDeclare(
		dp.Exchange,         //交换机名称
		"x-delayed-message", //交换机类型 :延时类型(插件)
		true,                //是否持久化
		false,               //是否自动删除
		false,               //是否具有排他性
		false,               //是否阻塞
		amqp.Table{
			"x-delayed-type": "direct", //延时消息类型: direct-点对点  fonout-广播   topic-路由匹配  headers-请求头匹配
		},
	)
	if err != nil {
		dp.DelayedProducterClose()
		return errors.New("声明延迟交换机失败:" + err.Error())
	}

	//声明延迟队列
	_, err = dp.Channel.QueueDeclare(
		dp.QueueName, //队列名称
		true,         //是否持久化
		false,        //是否自动删除
		false,        //是否具有排他性
		false,        //是否阻塞
		nil,          //额外属性
	)
	if err != nil {
		dp.DelayedProducterClose()
		return errors.New("声明延迟队列失败:" + err.Error())
	}

	//队列和交换机绑定
	err = dp.Channel.QueueBind(
		dp.QueueName,  //队列名称
		dp.RoutingKey, //路由key
		dp.Exchange,   //交换机名称
		false,         // 是否阻塞
		nil,           // 额外属性
	)
	if err != nil {
		dp.DelayedProducterClose()
		return errors.New("队列和交换机绑定失败:" + err.Error())
	}
	return nil
}

// 发消息 msg-消息内容   outTime-时间毫秒字符串类型 50秒 即 "50000"
func (dp *DelayedProducter) DelayedProducterSend(msg, outTime string) error {
	err := dp.Channel.Publish(
		dp.Exchange,   //交换机名
		dp.RoutingKey, //路由key
		false,         // 是否返回消息(匹配队列),如果为true, 会根据binding规则匹配queue,如未匹配queue,则把发送的消息返回给发送者
		false,         // 是否返回消息(匹配消费者),如果为true, 消息发送到queue后发现没有绑定消费者,则把发送的消息返回给发送者
		amqp.Publishing{ // 发送的消息,固定有消息体和一些额外的消息头,包中提供了封装对象
			ContentType: "text/plain", // 消息内容的类型
			Body:        []byte(msg),  // 消息内容
			Headers: map[string]interface{}{
				"x-delay": outTime, //消息交换机过期时间 毫秒
			},
		},
	)
	if err != nil {
		dp.DelayedProducterClose()
		return errors.New("队列和交换机绑定失败:" + err.Error())
	}
	return nil
}

func (dp *DelayedProducter) DelayedProducterClose() {
	dp.Conn.Close()
	dp.Channel.Close()
}

3.封装消费者代码

package mq

import (
	"errors"

	"github.com/streadway/amqp"
)

type DelayedCustomer struct {
	Conn    *amqp.Connection
	Channel *amqp.Channel
	// 队列名称
	QueueName string
	// 交换机
	Exchange string
	// routing Key
	RoutingKey string
	//MQ链接字符串
	Mqurl string
}

func (dc *DelayedCustomer) InitDelayedCustomer() (<-chan amqp.Delivery, error) {
	dc.Mqurl = "amqp://xxxooo:123456@127.0.0.1:5672/"
	dc.Exchange = "delayed-exchange" //交换机名
	dc.RoutingKey = "delay-key"      //路由key
	dc.QueueName = "delayed-queue"   //队列名称
	//创建连接
	var err error
	dc.Conn, err = amqp.Dial(dc.Mqurl)
	if err != nil {
		return nil, errors.New("连接失败:" + err.Error())
	}

	//创建通道
	dc.Channel, err = dc.Conn.Channel()
	if err != nil {
		dc.Conn.Close() //关闭连接
		return nil, errors.New("创建通道失败:" + err.Error())
	}

	//声明延迟队列
	_, err = dc.Channel.QueueDeclare(
		dc.QueueName, //队列名称
		true,         //是否持久化
		false,        //是否自动删除
		false,        //是否具有排他性
		false,        //是否阻塞
		nil,          //额外属性
	)
	if err != nil {
		dc.DelayedCustomerClose()
		return nil, errors.New("声明延迟队列失败:" + err.Error())
	}

	// 2.从队列获取消息(消费者只关注队列)consume方式会不断的从队列中获取消息
	return dc.Channel.Consume(
		dc.QueueName, // 队列名
		"",           // 消费者名,用来区分多个消费者,以实现公平分发或均等分发策略
		true,         // 是否自动应答
		false,        // 是否排他
		false,        // 是否接收只同一个连接中的消息,若为true,则只能接收别的conn中发送的消息
		false,        // 队列消费是否阻塞
		nil,          // 额外属性
	)

}

func (dc *DelayedCustomer) DelayedCustomerClose() {
	dc.Conn.Close()
	dc.Channel.Close()
}

4.生产者操作代码

package main

import (
	"fmt"
	mq "test-rabbitmq/common/rabbitmq"
)


func main() {
	
	var DelayedProducter mq.DelayedProducter
	err := DelayedProducter.InitDelayedProducter()
	if err != nil {
		fmt.Println(err.Error())
		return
	}
    //发送消息 
	err = DelayedProducter.DelayedProducterSend("消息111", "50000")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer DelayedProducter.DelayedProducterClose()

}

注意,如上时间参数是字符串

5.消费者代码

package main

import (
	"fmt"
	mq "test-rabbitmq/common/rabbitmq"
)

func main() {

	var DelayedCustomer mq.DelayedCustomer
	msgChanl, err := DelayedCustomer.InitDelayedCustomer()
	if err != nil {
		fmt.Println(err)
		return
	}
	defer DelayedCustomer.DelayedCustomerClose()
	for msg := range msgChanl {
		// 这里写你的处理逻辑
		// 获取到的消息是amqp.Delivery对象,从中可以获取消息信息
		fmt.Println(string(msg.Body))
		// msg.Ack(true) // 主动应答
	}

}

通过生产者发送不同延时消息,消费者能收到对应延时的消息,不会因为消息的前后顺序而阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值