fix: BatchError.Add() non thread safe (#3946)

master^2
chentong 9 months ago committed by GitHub
parent 5263805b3b
commit ec41880476
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,10 +1,14 @@
package errorx package errorx
import "bytes" import (
"bytes"
"sync"
)
type ( type (
// A BatchError is an error that can hold multiple errors. // A BatchError is an error that can hold multiple errors.
BatchError struct { BatchError struct {
mu sync.Mutex
errs errorArray errs errorArray
} }
@ -13,6 +17,9 @@ type (
// Add adds errs to be, nil errors are ignored. // Add adds errs to be, nil errors are ignored.
func (be *BatchError) Add(errs ...error) { func (be *BatchError) Add(errs ...error) {
be.mu.Lock()
defer be.mu.Unlock()
for _, err := range errs { for _, err := range errs {
if err != nil { if err != nil {
be.errs = append(be.errs, err) be.errs = append(be.errs, err)

@ -3,6 +3,7 @@ package errorx
import ( import (
"errors" "errors"
"fmt" "fmt"
"sync"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -33,7 +34,7 @@ func TestBatchErrorNilFromFunc(t *testing.T) {
func TestBatchErrorOneError(t *testing.T) { func TestBatchErrorOneError(t *testing.T) {
var batch BatchError var batch BatchError
batch.Add(errors.New(err1)) batch.Add(errors.New(err1))
assert.NotNil(t, batch) assert.NotNil(t, batch.Err())
assert.Equal(t, err1, batch.Err().Error()) assert.Equal(t, err1, batch.Err().Error())
assert.True(t, batch.NotNil()) assert.True(t, batch.NotNil())
} }
@ -42,7 +43,26 @@ func TestBatchErrorWithErrors(t *testing.T) {
var batch BatchError var batch BatchError
batch.Add(errors.New(err1)) batch.Add(errors.New(err1))
batch.Add(errors.New(err2)) batch.Add(errors.New(err2))
assert.NotNil(t, batch) assert.NotNil(t, batch.Err())
assert.Equal(t, fmt.Sprintf("%s\n%s", err1, err2), batch.Err().Error()) assert.Equal(t, fmt.Sprintf("%s\n%s", err1, err2), batch.Err().Error())
assert.True(t, batch.NotNil()) assert.True(t, batch.NotNil())
} }
func TestBatchErrorConcurrentAdd(t *testing.T) {
const count = 10000
var batch BatchError
var wg sync.WaitGroup
wg.Add(count)
for i := 0; i < count; i++ {
go func() {
defer wg.Done()
batch.Add(errors.New(err1))
}()
}
wg.Wait()
assert.NotNil(t, batch.Err())
assert.Equal(t, count, len(batch.errs))
assert.True(t, batch.NotNil())
}

Loading…
Cancel
Save