GO语言使用redis stream队列demo

19 篇文章 0 订阅

GO语言使用redis stream队列demo

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

var client *redis.Client
var ctx context.Context
var key = "my_streamKey2"        //key
var myConsumer = "my_consumer"   //消费者
var group = "my_group"           // 消费者组的名称
var maxLength = int64(10000 * 1) // 保留最新的100条消息
func main() {
	Close()
	Init()
	go NoAck()
	for {
		XAdd()
		time.Sleep(time.Millisecond * 1)
	}

}
func Close() {
	// 创建一个通道来接收信号
	sigCh := make(chan os.Signal, 1)
	// 监听指定的信号
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)

	// 启动一个 goroutine 来处理接收到的信号
	go func() {
		// 等待信号
		sig := <-sigCh
		fmt.Println("接收到信号:", sig)

		// 在这里执行程序关闭前的清理操作
		// 在这里编写你的程序逻辑
		err := client.Close()
		if err != nil {
			fmt.Println("关闭redis err:", err)
			return
		}
		fmt.Println("关闭redis")
		// 退出程序
		os.Exit(0)
	}()
}
func Init() {
	// 创建Redis客户端
	client = redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:6379", // Redis服务器地址和端口
		Password: "123456!",          // Redis服务器密码,如果有的话
		DB:       12,                   // Redis数据库索引
		PoolSize: 10,                    // 连接池大小
	})
	ctx = client.Context()
	groupInit()
	// 启动消费者
	go func() {
		for {
			streams, err := client.XReadGroup(ctx, &redis.XReadGroupArgs{
				Group:    group,              // 消费者组的名称
				Consumer: myConsumer,         // 消费者的名称
				Streams:  []string{key, ">"}, // Stream的名称和ID
				Count:    int64(1000),        // 要读取的消息数量
				Block:    time.Second * 1,    // 阻塞时间,0表示不阻塞
			}).Result()

			if err != nil {
				//fmt.Println("XReadGroup error:", err)
				continue
			}

			for _, stream := range streams {
				streamName := stream.Stream
				fmt.Println("获取消息 长度", len(stream.Messages))
				for _, message := range stream.Messages {
					messageID := message.ID
					messageValues := message.Values
					fmt.Println("读取到Stream: streamName=", streamName, " messageID=", messageID, " messageValues=", messageValues)

					// 标记消息已经被消费者读取
					err := client.XAck(ctx, key, group, messageID).Err()
					if err != nil {
						fmt.Println("XAck error:", err)
						return
					}
					fmt.Println("消息已经被标记为已读取")
				}
			}
			xTrimMaxLen()

		}
	}()

}
func xTrimMaxLen() {
	// 修剪Stream
	trimCmd := client.XTrimMaxLen(ctx, key, maxLength)
	_, err := trimCmd.Result()
	if err != nil {
		fmt.Println("修剪Stream失败:", err)
		//return
	}
	//fmt.Println("修剪Stream结果:", trimmed)
}
func XAdd() {
	// 发布消息到Stream
	_, err := client.XAdd(ctx, &redis.XAddArgs{
		Stream: key, // Stream的名称
		Values: map[string]interface{}{
			"key1": "value1",
			"key2": strconv.FormatInt(time.Now().UnixMilli(), 10),
		},
	}).Result()

	if err != nil {
		fmt.Println("XAdd error:", err)
		return
	}

	//fmt.Println("Stream ID:", streamID)
}

/*
*
读取未被ack的消息
*/
func NoAck() {
	fmt.Println("开始读取未被ack的消息")
	streams, err := client.XReadGroup(ctx, &redis.XReadGroupArgs{
		Group:    group,              // 消费者组的名称
		Consumer: myConsumer,         // 消费者的名称
		Streams:  []string{key, ">"}, // Stream的名称和ID
		Count:    10000,              // 要读取的消息数量
		NoAck:    true,               // 设置为true,表示读取未被ack的消息
		Block:    0,                  // 阻塞时间,0表示不阻塞
	}).Result()

	if err != nil {
		fmt.Println("没有读取到未被ack的消息 error:", err)
		return
	}

	for _, stream := range streams {
		streamName := stream.Stream
		for _, message := range stream.Messages {
			messageID := message.ID
			messageValues := message.Values
			fmt.Println("读取到Stream: streamName=", streamName, " messageID=", messageID, " messageValues=", messageValues)

			// 标记消息已经被消费者读取
			err := client.XAck(ctx, key, group, messageID).Err()
			if err != nil {
				fmt.Println("未被ack的消息 XAck error:", err)
				return
			}
			fmt.Println("未被ack的消息已经被标记为已读取")
		}
	}
}
func groupInit() {
	// 判断key是否存在
	existsKey, err := client.Exists(ctx, key).Result()
	if err != nil {
		fmt.Println("Exists error:", err)
		return
	}

	if existsKey == 1 {
		fmt.Println("Key存在")
		// 获取所有消费者组信息
		groups, err := client.XInfoGroups(ctx, key).Result()
		if err != nil {
			fmt.Println("XInfoGroups error:", err)
			return
		}

		// 判断目标消费者组是否存在

		exists := false
		for _, g := range groups {
			if g.Name == group {
				exists = true
				break
			}
		}
		if exists {
			fmt.Println("消费者组存在")
		} else {
			fmt.Println("消费者组不存在")
			// 创建Stream
			streamCreated, err := client.XGroupCreateMkStream(ctx, key, group, "0").Result()
			if err != nil {
				fmt.Println("创建消费组 XGroupCreateMkStream error:", err)
			}
			fmt.Println("创建消费组:", streamCreated)
		}
	} else if existsKey == 0 {
		fmt.Println("Key不存在")
		// 创建Stream
		streamCreated, err := client.XGroupCreateMkStream(ctx, key, group, "0").Result()
		if err != nil {
			fmt.Println("创建消费组 XGroupCreateMkStream error:", err)
		}
		fmt.Println("创建消费组:", streamCreated)

	} else {
		fmt.Println("Exists返回值异常")
	}

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot提供了对Redis Stream队列的支持。Redis Stream是一个高效的持久化消息队列,可以用于实现发布-订阅模式、任务队列等应用场景。 要在Spring Boot中使用Redis Stream队列,需要进行以下步骤: 1. 添加Redis和Spring Data Redis的依赖:在`pom.xml`文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 配置Redis连接信息:在`application.properties`或`application.yml`文件中配置Redis连接信息,包括主机、端口、密码等。 ```properties spring.redis.host=your_redis_host spring.redis.port=your_redis_port spring.redis.password=your_redis_password ``` 3. 创建Redis Stream队列:在Spring Boot中,可以使用`StreamOperations`接口来操作Redis Stream队列。可以通过自动注入`RedisTemplate`或`StringRedisTemplate`来获取`StreamOperations`对象。 ```java @Autowired private RedisTemplate<String, String> redisTemplate; ... StreamOperations<String, String, String> streamOperations = redisTemplate.opsForStream(); ``` 4. 发布消息到Redis Stream队列使用`XADD`命令将消息发布到Redis Stream队列中。 ```java Map<String, String> message = new HashMap<>(); message.put("key1", "value1"); message.put("key2", "value2"); streamOperations.add("your_stream_key", message); ``` 5. 消费Redis Stream队列消息:使用`XREADGROUP`命令消费Redis Stream队列中的消息。 ```java Consumer<String, String> consumer = StreamOffset.create("your_stream_key", ReadOffset.lastConsumed()); while (true) { List<MapRecord<String, String, String>> records = streamOperations.read(consumer, StreamReadOptions.empty()); for (MapRecord<String, String, String> record : records) { // 处理消息 System.out.println(record.getValue()); } } ``` 以上是使用Spring Boot操作Redis Stream队列的基本步骤,你可以根据实际需求进行修改和扩展。希望对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值