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) // 主动应答
}
}
通过生产者发送不同延时消息,消费者能收到对应延时的消息,不会因为消息的前后顺序而阻塞。
1360

被折叠的 条评论
为什么被折叠?



