1
0
mirror of https://github.com/redis/go-redis.git synced 2025-11-10 00:00:57 +03:00

fix(sentinel): handle empty address (#3577)

* improvements

* linter fixes

* prevention on unnecessary allocations in case of bad configuration

* Test/Benchmark, old code with safety harness preventing panic

---------

Co-authored-by: manish <manish.sharma@manifestit.io>
Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
This commit is contained in:
manish
2025-11-05 20:23:45 +05:30
committed by GitHub
parent 284d93a4b3
commit 60b748bf1a
3 changed files with 108 additions and 1 deletions

View File

@@ -106,3 +106,7 @@ func (c *ModuleLoadexConfig) ToArgs() []interface{} {
func ShouldRetry(err error, retryTimeout bool) bool {
return shouldRetry(err, retryTimeout)
}
func JoinErrors(errs []error) string {
return joinErrors(errs)
}

View File

@@ -843,6 +843,11 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
}
}
// short circuit if no sentinels configured
if len(c.sentinelAddrs) == 0 {
return "", errors.New("redis: no sentinels configured")
}
var (
masterAddr string
wg sync.WaitGroup
@@ -890,10 +895,12 @@ func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) {
}
func joinErrors(errs []error) string {
if len(errs) == 0 {
return ""
}
if len(errs) == 1 {
return errs[0].Error()
}
b := []byte(errs[0].Error())
for _, err := range errs[1:] {
b = append(b, '\n')

View File

@@ -682,3 +682,99 @@ func compareSlices(t *testing.T, a, b []string, name string) {
}
}
}
type joinErrorsTest struct {
name string
errs []error
expected string
}
func TestJoinErrors(t *testing.T) {
tests := []joinErrorsTest{
{
name: "empty slice",
errs: []error{},
expected: "",
},
{
name: "single error",
errs: []error{errors.New("first error")},
expected: "first error",
},
{
name: "two errors",
errs: []error{errors.New("first error"), errors.New("second error")},
expected: "first error\nsecond error",
},
{
name: "multiple errors",
errs: []error{
errors.New("first error"),
errors.New("second error"),
errors.New("third error"),
},
expected: "first error\nsecond error\nthird error",
},
{
name: "nil slice",
errs: nil,
expected: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := redis.JoinErrors(tt.errs)
if result != tt.expected {
t.Errorf("joinErrors() = %q, want %q", result, tt.expected)
}
})
}
}
func BenchmarkJoinErrors(b *testing.B) {
benchmarks := []joinErrorsTest{
{
name: "empty slice",
errs: []error{},
expected: "",
},
{
name: "single error",
errs: []error{errors.New("first error")},
expected: "first error",
},
{
name: "two errors",
errs: []error{errors.New("first error"), errors.New("second error")},
expected: "first error\nsecond error",
},
{
name: "multiple errors",
errs: []error{
errors.New("first error"),
errors.New("second error"),
errors.New("third error"),
},
expected: "first error\nsecond error\nthird error",
},
{
name: "nil slice",
errs: nil,
expected: "",
},
}
for _, bm := range benchmarks {
b.Run(bm.name, func(b *testing.B) {
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
result := redis.JoinErrors(bm.errs)
if result != bm.expected {
b.Errorf("joinErrors() = %q, want %q", result, bm.expected)
}
}
})
})
}
}