✨ Refactor: Convert WaitErr to an interface and add New constructor
This commit is contained in:
parent
a68fc26481
commit
edc34062e9
4 changed files with 47 additions and 42 deletions
53
waiterr.go
53
waiterr.go
|
|
@ -5,23 +5,43 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
func New() WaitErr {
|
||||
var we waitErr
|
||||
we.errCh = make(chan error, 1)
|
||||
|
||||
return &we
|
||||
}
|
||||
|
||||
// WaitErr provides a way to run multiple goroutines and wait for their completion,
|
||||
// collecting any errors they return.
|
||||
type WaitErr interface {
|
||||
// Go runs f in its own goroutine. When f returns, its error is stored, and returned
|
||||
// with [WaitErr.Wait].
|
||||
Go(f func() error)
|
||||
// WaitForError waits for the first error to be returned by one of our go routines, and immediately returns
|
||||
// with that error. If all functions return successfully, a nil is returned.
|
||||
WaitForError() error
|
||||
// Wait for all current goroutines to finish. Return an error that combines all errors returned
|
||||
// in the group so far (if any).
|
||||
Wait() error
|
||||
// Unwrap returns all non-nil errors returned by our functions.
|
||||
// If no errors were returned, or all errors are nil, it returns nil.
|
||||
Unwrap() []error
|
||||
}
|
||||
|
||||
// WaitErr wraps a [sync.WaitGroup] with error handling.
|
||||
type WaitErr struct {
|
||||
wg sync.WaitGroup
|
||||
errs []error
|
||||
mut sync.RWMutex
|
||||
firstErr error
|
||||
firstErrOnce sync.Once
|
||||
errCh chan error // Buffered channel of size 1
|
||||
initErrChOnce sync.Once
|
||||
type waitErr struct {
|
||||
wg sync.WaitGroup
|
||||
errs []error
|
||||
mut sync.RWMutex
|
||||
firstErr error
|
||||
firstErrOnce sync.Once
|
||||
errCh chan error // Buffered channel of size 1
|
||||
}
|
||||
|
||||
// Go runs f in its own goroutine. When f returns, its error is stored, and returned
|
||||
// with [WaitErr.Wait].
|
||||
func (we *WaitErr) Go(f func() error) {
|
||||
we.initErrChOnce.Do(func() {
|
||||
we.errCh = make(chan error, 1)
|
||||
})
|
||||
func (we *waitErr) Go(f func() error) {
|
||||
wrap := func() {
|
||||
err := f()
|
||||
|
||||
|
|
@ -48,10 +68,7 @@ func (we *WaitErr) Go(f func() error) {
|
|||
|
||||
// WaitForError waits for the first error to be returned by one of our go routines, and immediately returns
|
||||
// with that error. If all functions return successfully, a nil is returned. It will panic if called before Go.
|
||||
func (we *WaitErr) WaitForError() error {
|
||||
if we.errCh == nil {
|
||||
panic("WaitForError called before Go")
|
||||
}
|
||||
func (we *waitErr) WaitForError() error {
|
||||
// Check if an error has already been set
|
||||
we.mut.RLock()
|
||||
if we.firstErr != nil {
|
||||
|
|
@ -82,7 +99,7 @@ func (we *WaitErr) WaitForError() error {
|
|||
|
||||
// Wait for all current goroutines to finish. Return an error that combines all errors returned
|
||||
// in the group so far (if any).
|
||||
func (we *WaitErr) Wait() error {
|
||||
func (we *waitErr) Wait() error {
|
||||
we.wg.Wait()
|
||||
we.mut.RLock()
|
||||
defer we.mut.RUnlock()
|
||||
|
|
@ -91,7 +108,7 @@ func (we *WaitErr) Wait() error {
|
|||
|
||||
// Unwrap returns all non-nil errors returned by our functions.
|
||||
// If no errors were returned, or all errors are nil, it returns nil.
|
||||
func (we *WaitErr) Unwrap() []error {
|
||||
func (we *waitErr) Unwrap() []error {
|
||||
errs := make([]error, 0, len(we.errs))
|
||||
for _, e := range we.errs {
|
||||
if e != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue