zset实现延时队列

一、zset相关操作

zrangebyscore:从zset拿出区间在[n,m]内的元素值
zadd:往zset添加一个元素
zrem:删除一个元素


多消费者异步消费数据的时候,先从zset拿到数据,然后删除数据,最后再去消费数据,这样可以确保任务不被其他消费者消费到

 

 

package delayqueue

import (
    "fmt"
    "log"
    "math/rand"
    "time"

    "github.com/garyburd/redigo/redis"

    "Project_A/json"
)
type redisClient struct {
    cli redis.Conn
}

func NewRedis() *redisClient{
    conn,err:=redis.Dial("tcp","127.0.0.1:6379")
    if err!=nil{
        log.Println("redis err:%v",err)
        panic(err)
    }
    return &redisClient{cli: conn}
}

type TaskMsg struct {
    Name string
    DelayTime int64
}

func (c *redisClient)AddTask(msg *TaskMsg, dealTime int64) {
    key := "DelayQueue"
    data,err:=json.Marshal(msg)
    if err!=nil{
        fmt.Errorf("AddTask err:%v",err)
        return
    }
    // 将延期的时间作为score,写进zset
    ret,err:=c.cli.Do("zadd", key, dealTime,data )
    if err!=nil{
        fmt.Errorf("%v",err)
        return
    }
    if ret!=0{
        fmt.Errorf("%v msg:%v",ret,msg)
    }
}
func (c *redisClient)DelTask(value string) int{
    key := "DelayQueue"
    ret, err := redis.Int(c.cli.Do("zrem", key, value))
    if err != nil {
        panic(err)
    }
    return ret
}

func (c *redisClient)GetTask() []string{
    key := "DelayQueue"
    nowTime := time.Now().Unix()
    // zrangebyscore 从zset拿出score在[0,nowTime]的元素
    ret, err := redis.Strings(c.cli.Do("zrangebyscore", key, 0, nowTime, "limit", 0, 1))
    if err != nil {
        fmt.Errorf("GetTask err:%v",err)
    }
    return ret
}

func (c *redisClient)producer(count int) {
    for i:=0;i<count;i++ {
        dealTime := int64(rand.Intn(5)) + time.Now().Unix()
        taskName := fmt.Sprintf("task_%v",i)
        task:=&TaskMsg{
            Name: taskName,
            DelayTime: dealTime,
        }
        c.AddTask(task,dealTime)
        fmt.Printf("%v\n",task)
    }
}
// 消费者
func (c *redisClient) consumer() {
    for {
        tasks := c.GetTask()
        if len(tasks) <= 0 {
            time.Sleep(time.Second * 1)
            continue
        }
        fmt.Printf("now time:%v,get task:%v",time.Now().Unix(),tasks[0])
        // 如果当前抢redis队列成功,
        if c.DelTask(tasks[0]) > 0 {
            task:=&TaskMsg{}
            err:=json.Unmarshal([]byte(tasks[0]),task)
            if err!=nil{
                fmt.Errorf("unmarshal err:%v",err)
                return
            }
            handleMessage(task)
        }
    }
}

// 处理任务用函数
func handleMessage(msg *TaskMsg) {
    fmt.Printf("handleMessage: %s, now time:%v,require time: %d \n", msg.Name,time.Now().Unix(), msg.DelayTime)
}

func Test(){
    //https://juejin.cn/post/6844904003810099208
    svr:=NewRedis()
    svr.producer(10)
    svr.consumer()
}

 

 
posted @ 2022-06-06 15:01  知道了呀~  阅读(342)  评论(0编辑  收藏  举报