go-redis icon indicating copy to clipboard operation
go-redis copied to clipboard

XREADs with BLOCK 0 on multiple consecutive Redis restarts exceed retries

Open Al2Klimov opened this issue 2 years ago • 2 comments

@lippserd just had the observation that blocking XREADs without timeouts (BLOCK 0) on multiple consecutive Redis restarts and I/O timeouts exceeds Go-Redis internal retries and eventually leads to errors. @julianbrost looked at this for clarification, here is his finding:

go-redis only considers a command successful when it returned something, so a successfully started blocking XREAD consumes a retry attempt each time the underlying Redis connection is terminated. If this happens often before any element appears in the stream, this error is propagated.

Expected Behavior

Successfully sent XREADs with BLOCK reset the internal retries.

Current Behavior

Successfully sent XREADs with BLOCK just failed while reading consume internal retries.

Possible Solution

Steps to Reproduce

Context (Environment)

refs Icinga/icingadb#504

Al2Klimov avatar Jun 27 '22 16:06 Al2Klimov

Dear maintainers,

any objections against extending Cmder (or just XStreamSliceCmd) by a flag for whether successfully written and one for whether that's enough?

So baseClient#process could communicate with baseClient#_process and set attempt=-1 if needed.

Al2Klimov avatar Jun 27 '22 16:06 Al2Klimov

And finally I could reproduce it as well:

  1. Run the below program
  2. Every time it prints success restart your Redis server
  3. It should not survive 4 restarts
package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v9"
	"net"
	"time"
)

func main() {
	var d net.Dialer

	err := redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
		Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) {
			for {
				conn, err := d.DialContext(ctx, network, addr)
				if err != nil {
					fmt.Println(err)
					time.Sleep(time.Second)
					continue
				}

				fmt.Println("success")
				return conn, err
			}
		},
		ReadTimeout: time.Hour,
		PoolSize:    1,
	}).XRead(context.Background(), &redis.XReadArgs{
		Streams: []string{"block0", "$"},
		Block:   0,
	}).Err()
	if err != nil {
		panic(err)
	}
}

Al2Klimov avatar Jul 05 '22 09:07 Al2Klimov

This issue is marked stale. It will be closed in 30 days if it is not updated.

github-actions[bot] avatar Sep 22 '23 00:09 github-actions[bot]