go通过rabbitmq实现延迟队列

延时队列的应用场景有很多,比如:订单在十分钟之内未支付则自动取消。
使用的go包是:github.com/streadway/amqp

下面展示主要的代码

生成队列的代码如下:
两个重点:
1、设置队列过期时间(包括队列和单个消息的过期时间,两者都设置的话取短的那个)
2、指定队列里面的消息过期后发送到哪个死信交换机,以及绑定规则。

【注意】
修改了队列参数后(比如修改队列的过期时间),需要把旧的队列删掉,才能重新生成新的队列。不然生产消息会提示:Exception (504) Reason: “channel/connection is not open”

//simple 模式下 队列生产(修改队列参数,需要删掉队列,重新生成队列才能生效)
func (r *RabbitMQ) PublishSimple(message string) {
	//1.申请队列,如果队列不存在会自动创建,存在则跳过创建
	//额外属性
	var args = make(map[string]interface{})
	args["x-message-ttl"] = 20000                            //设置队列的过期时间(单位是毫秒)
	args["x-dead-letter-exchange"] = "dead_message_exchange" // 指定死信交换机
	args["x-dead-letter-routing-key"] = "dead_message_key"   // 指定死信routing-key
	_, err := r.channel.QueueDeclare(
		r.QueueName,
		//是否持久化
		true,
		//是否自动删除
		false,
		//是否具有排他性
		false,
		//是否阻塞处理
		false,
		//额外的属性
		args,
	)
	if err != nil {
		fmt.Println(err)
	}
	//调用channel 发送消息到队列中
	r.channel.Publish(
		r.Exchange,
		r.QueueName,
		//如果为true,根据自身exchange类型和routekey规则无法找到符合条件的队列会把消息返还给发送者
		false,
		//如果为true,当exchange发送消息到队列后发现队列上没有消费者,则会把消息返还给发送者
		false,
		amqp.Publishing{
			//Expiration:  "10000", //针对单个消息,单位是毫秒(如果队列也设置了过期时间,就以两者比较短的时间为准)
			ContentType: "text/plain",
			Body:        []byte(message),
		})
}

生产者调用上面的方法:

package main

import (
	"go_rabbitmq/rabbitmq"
)
func main() {
	//只需要设置队列名称即可
	rabbitmq := rabbitmq.NewRabbitMQSimple("cowboyQueue_swl")

	//简单模式下,直接用这个测试是否能正常消费
	rabbitmq.PublishSimple("cowbouy very busy!")
	fmt.Println("发送成功")
}

然后登陆rabbit后台查看
在这里插入图片描述
在这里插入图片描述

接下来就是要生成死信交换机和死信队列

通过消费者进程创建交换机和绑定关系(生产者进程最多只创建交换机,因为生者者只负责把消息投递给交换机)
重点:注意durable和exclusive的用法和关系。
1、durable为true的时候连接关闭(消费者进程退出)不删除队列。前提是exclusive为false。
2、exclusive为true 代表只被一个连接(connection)使用,而且当连接关闭后队列即被删除(消费者进程退出即删除队列)。exclusive设置了true的话,即使durable为true队列也不会持久存在。

死信队列消费者进程代码

//死信队列消费者(消费者进程负责创建交换机、队列以及绑定关系。无法在生产者进程去创建队列和绑定关系,生产者只负责把消息投递给交换机。)
func (r *RabbitMQ) ConsumeDeadQueue() {

	//1.不存在该交换机则创建交换机
	err := r.channel.ExchangeDeclare(
		r.Exchange,
		"direct",
		true,
		false,
		false,
		false,
		nil,
	)
	r.failOnErr(err, "Failed to declare an exchange")
	//2.不存在则创建队列
	q, err := r.channel.QueueDeclare(
		r.QueueName,
		true, //durable为true的时候连接关闭(消费者进程退出)不删除队列。前提是exclusive为false
		false,
		false, //⭐重点:exclusive为true 代表只被一个连接(connection)使用,而且当连接关闭后队列即被删除(消费者进程退出即删除队列)。exclusive设置了true的话,即使durable为true队列也不会持久存在。
		false,
		nil,
	)
	fmt.Printf("q: %v\n", q)
	fmt.Printf("err: %v\n", err)
	r.failOnErr(err, "Failed to declare a queue")

	//3.绑定队列和交换机
	err = r.channel.QueueBind(
		q.Name,
		r.Key,
		r.Exchange,
		false,
		nil,
	)
	r.failOnErr(err, "Failed to bind")

	//消费消息
	messges, err := r.channel.Consume(
		q.Name,
		"",
		true,
		false,
		false,
		false,
		nil,
	)
	r.failOnErr(err, "Failed to consume")
	forever := make(chan bool)

	go func() {
		for d := range messges {
			log.Printf("Received a message: %s", d.Body)
		}
	}()

	fmt.Println("退出请按 CTRL+C")
	<-forever
}
package main

import "go_rabbitmq/rabbitmq"

func main() {
	//执行 go build -o xxx.exe 生成消费进程
	rabbitmq := rabbitmq.NewRabbitMQDead("cowboy_dead_queue", "dead_message_exchange", "dead_message_key")
	rabbitmq.ConsumeDeadQueue()
}

验证

接下来就可以重新执行生产者的代码,看消息到期后,会不会发送到死信队列。
最后开启死信队列的消费者进程,不断消费死信队列中的消息,就能达到延迟队列的效果。

在这里插入图片描述
在这里插入图片描述

技巧

查看消费者进程是否存在?以及如何真正杀死消费者进程?
在这里插入图片描述

在这里插入图片描述

总结

总共需要写两个进程:
一个正常队列的生产者进程(设置好超时过期时间,指定消息过期后投递的死信交换机,和绑定路由),
一个死信队列的消费者进程(创建死信交换机、死信队列、绑定关系)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值