1

Good afternoon. I am trying to solve a queue problem with radis stream.

Task description: we need to implement a queue to store the data that we will send to the user's email.

How it works: I have a queue, when I create a queue, I also create a group that I will work with, also inside will be a worker that will check messages with status pending through ticker to resend data to the queue

Problems:

  1. CheckPending method - when I call the method to check pending messages, I get a blank response, such as: []
  2. How can I make CheckPending work in the background once, say every minute, to check the data for pending status and re-add it to the list?

Queue.go

package main

import (
    "context"
    "errors"
    "github.com/go-redis/redis/v8"
    "github.com/rs/zerolog"
    "strings"
    "sync"
    "time"
)

// ErrNoGroup you can get this error if you forget to create the group, but you still send a request for data
var ErrNoGroup = errors.New("no group has been created")

// ErrNoStream you can get this error if you forget to create a thread, but still send a request to retrieve data
var ErrNoStream = errors.New("")

type Options struct {
    Name   string
    Redis  *redis.Client
    Logger *zerolog.Logger
}

type Queue struct {
    Client *redis.Client
    Name   string
    Group  string
    WG     sync.WaitGroup
    Logger *zerolog.Logger
}

const interval = 500

func New(options *Options) *Queue {
    logger := options.Logger.With().Str("service", "queue").Logger()
    q := &Queue{
        Client: options.Redis,
        Name:   options.Name + "stream",
        Group:  options.Name + "group",
        Logger: &logger,
    }

    // This command creates a new consumer group
    err := q.Client.XGroupCreateMkStream(context.Background(), q.Name, q.Group, "0").Err()
    if err != nil {
        return nil
    }

    ctx, cancel := context.WithCancel(context.Background())
    q.WG.Add(1)
    go func() {
        time.Sleep(60 * interval * time.Millisecond)
        defer q.WG.Done()
        cancel()
    }()

    errP := q.CheckPending(ctx)
    if errP != nil {
        return nil
    }

    return q
}


// CheckPending TODO: not found data
func (q *Queue) CheckPending(ctx context.Context) error {
    l := q.methodLogger(ctx, "Queue CheckPending")
    l.Debug().Msg("check pending task")

    ticker := time.NewTicker(interval * time.Millisecond)
    for {
        select {
        case <-ticker.C:
            pending, err := q.Client.XPendingExt(ctx, &redis.XPendingExtArgs{
                Stream: q.Name,
                Group:  q.Group,
                Start:  "-",
                End:    "+",
                Count:  10,
            }).Result()

            if err != nil {
                if strings.HasPrefix(err.Error(), "NOGROUP") {
                    return ErrNoGroup
                }
                if strings.HasPrefix(err.Error(), "NOSTREAM") {
                    return ErrNoStream
                }

                return err
            }

            if len(pending) == 0 {
                return nil
            }

            fmt.Print(pending) // return []
            break
        case <-ctx.Done():
            return nil
        }
    }
}

Main.go

func main() {
    rds := redis.NewClient(&redis.Options{
        Addr: ":6379",
    })

    q := queue.New(rds, "email")
    data := map[string]interface{}{"email": "email@gmail.com", "message": "We have received you order and we are working on it."}

    err := q.Add(context.Background(), data)

    fmt.Print(err)
    q.Read(context.TODO())
    // Example 
    err := q.CheckPending(context.TODO()) // return []
    if err != nil {
        fmt.Print(err)
    }
}

In my redis repository I have data that I put there three days ago which I have not interacted with in any way, but I closed only a selection using the XACK command Why can't I get data out of the repository via my CheckPending method?

alex
  • 524
  • 2
  • 11

0 Answers0