go-redis
go-redis copied to clipboard
client hangs when non-blocking XREAD on empty streams
Expected Behavior
Client should return an empty response.
Current Behavior
Client blocks forever, even with timeouts set..
Possible Solution
Will investigate.
Steps to Reproduce
package main
import (
"context"
"time"
"github.com/go-redis/redis/v8"
)
func main() {
re := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
ReadTimeout: 1 * time.Second,
WriteTimeout: 1 * time.Second,
MaxRetries: 0,
PoolSize: 10,
PoolTimeout: 1 * time.Second,
DialTimeout: 1 * time.Second,
})
println("connected")
read := re.XRead(context.Background(), &redis.XReadArgs{
Streams: []string{"hi", "0"},
})
println("unreachable")
println(read.Val())
}
Same here with XReadGroup
: It does not matter if block
parameter is 0
or 1
. It always blocks
set block argument
println("connected")
read := re.XRead(context.Background(), &redis.XReadArgs{
Streams: []string{"hi", "0"},
Block: time.Millisecond * 10, // set block arg
})
println("unreachable")
println(read.Val())
why i not set block arg or set it to 0 or 1 do not work? if i not set block it should return immediately!
I have found the same problem problem with XReadGroup, the solution for me was to set a small timeout and catch the timeout errors apart.
readMessages, err := client.XReadGroup(ctx, &redis.XReadGroupArgs{
Group: groupName,
Consumer: consumerName,
Streams: []string{streamName, ">"},
Count: 0,
Block: 1,
NoAck: false,
}).Result()
if err != nil && !os.IsTimeout(err) {
return []redis.XMessage{}, err
}
Never the less the expected behavior should be that without specifying a Block value, it should not block the stream
I think I have the same problem z with pub/sub mechanism
I also face the same problem, why use xread and xreadgroup will stuck, and i cant read any message. that's so shocking me.
The API design of Redis Stream is damn... The default behavior of XREADGROUP of Redis is non-blocking, unless we set [BLOCK milliseconds]
. Therefore, it is natural to think of using zero value in Go as the default value (default behavior). However, we take it for granted that this is right to 'just ignore setting the value of Block
in XReadGroupArgs
'.
The lib do this (as below) in XReadGroup
, which means no value <=> set [BLOCK 0]
:
if a.Block >= 0 {
args = append(args, "block", int64(a.Block/time.Millisecond))
keyPos += 2
}
The correct solution maybe assigns a negative value to Block
like -time.Millisecond
(but I would say it again that the API is damn...)