mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
common: Update ErrorCollector to use mutex and simplify error collection in concurrent operations (#2090)
* refactor: Update ErrorCollector to use mutex and simplify error collection in concurrent operations * glorious: nits * linter: fix * another find * Apply suggestion from @gbjk Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * Apply suggestion from @gbjk Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * one liner defer * Update common/common.go Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> * gk: nits * Update common/common_test.go Co-authored-by: Scott <gloriousCode@users.noreply.github.com> * thrasher-: nits --------- Co-authored-by: shazbert <ryan.oharareid@thrasher.io> Co-authored-by: Gareth Kirwan <gbjkirwan@gmail.com> Co-authored-by: shazbert <shazbert@DESKTOP-3QKKR6J.localdomain> Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
@@ -553,31 +553,33 @@ func ExcludeError(err, excl error) error {
|
||||
}
|
||||
|
||||
// ErrorCollector allows collecting a stream of errors from concurrent go routines
|
||||
// Users should call e.Wg.Done and send errors to e.C
|
||||
type ErrorCollector struct {
|
||||
C chan error
|
||||
Wg sync.WaitGroup
|
||||
errs error
|
||||
wg sync.WaitGroup
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
// CollectErrors returns an ErrorCollector with WaitGroup and Channel buffer set to n
|
||||
func CollectErrors(n int) *ErrorCollector {
|
||||
e := &ErrorCollector{
|
||||
C: make(chan error, n),
|
||||
}
|
||||
e.Wg.Add(n)
|
||||
return e
|
||||
}
|
||||
|
||||
// Collect runs waits for e.Wg to be Done, closes the error channel, and return a error collection
|
||||
// Collect waits for the internal wait group to be done and returns an error collection
|
||||
// State is reset after each Collect, so successive calls are okay
|
||||
func (e *ErrorCollector) Collect() (errs error) {
|
||||
e.Wg.Wait()
|
||||
close(e.C)
|
||||
for err := range e.C {
|
||||
if err != nil {
|
||||
errs = AppendError(errs, err)
|
||||
}
|
||||
e.wg.Wait()
|
||||
e.m.Lock()
|
||||
defer func() { e.errs = nil; e.m.Unlock() }()
|
||||
return e.errs
|
||||
}
|
||||
|
||||
// Go runs a function in a goroutine and collects any error it returns
|
||||
func (e *ErrorCollector) Go(f func() error) {
|
||||
if err := NilGuard(f); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
e.wg.Go(func() {
|
||||
if err := f(); err != nil {
|
||||
e.m.Lock()
|
||||
e.errs = AppendError(e.errs, err)
|
||||
e.m.Unlock()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// StartEndTimeCheck provides some basic checks which occur
|
||||
|
||||
@@ -590,23 +590,22 @@ func TestGenerateRandomString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestErrorCollector exercises the error collector
|
||||
func TestErrorCollector(t *testing.T) {
|
||||
e := CollectErrors(4)
|
||||
var e ErrorCollector
|
||||
require.Panics(t, func() { e.Go(nil) }, "Go with nil function must panic")
|
||||
for i := range 4 {
|
||||
go func() {
|
||||
e.Go(func() error {
|
||||
if i%2 == 0 {
|
||||
e.C <- errors.New("Collected error")
|
||||
} else {
|
||||
e.C <- nil
|
||||
return errors.New("collected error")
|
||||
}
|
||||
e.Wg.Done()
|
||||
}()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
v := e.Collect()
|
||||
errs, ok := v.(*multiError)
|
||||
require.True(t, ok, "Must return a multiError")
|
||||
assert.Len(t, errs.Unwrap(), 2, "Should have 2 errors")
|
||||
assert.NoError(t, e.Collect(), "should return nil when a previous collection emptied the errors")
|
||||
}
|
||||
|
||||
// TestBatch ensures the Batch function does not regress into common behavioural faults if implementation changes
|
||||
|
||||
Reference in New Issue
Block a user