Skip to content

Commit

Permalink
Add WithFailFast() (#118)
Browse files Browse the repository at this point in the history
In #104, a "FailFast" option is
likely going to be added to iterators that, on error, stops running
additional tasks and returns the error that caused the first failure.

"FailFast" seems is a pretty standard description for this behavior, and
combining two common options into a single option with a more
discoverable name seems like a nice thing to do before 1.0.
  • Loading branch information
camdencheek authored Jun 1, 2023
1 parent 8e5ba59 commit 995000d
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 2 deletions.
10 changes: 10 additions & 0 deletions pool/context_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ func (p *ContextPool) WithCancelOnError() *ContextPool {
return p
}

// WithFailFast is an alias for the combination of WithFirstError and
// WithCancelOnError. By default, the errors from all tasks are returned and
// the pool's context is not canceled until the parent context is canceled.
func (p *ContextPool) WithFailFast() *ContextPool {
p.panicIfInitialized()
p.WithFirstError()
p.WithCancelOnError()
return p
}

// WithMaxGoroutines limits the number of goroutines in a pool.
// Defaults to unlimited. Panics if n < 1.
func (p *ContextPool) WithMaxGoroutines(n int) *ContextPool {
Expand Down
4 changes: 2 additions & 2 deletions pool/context_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ func TestContextPool(t *testing.T) {
require.NotErrorIs(t, err, err2)
})

t.Run("WithFirstError and WithCancelOnError", func(t *testing.T) {
t.Run("WithFailFast", func(t *testing.T) {
t.Parallel()
p := New().WithContext(bgctx).WithFirstError().WithCancelOnError()
p := New().WithContext(bgctx).WithFailFast()
p.Go(func(ctx context.Context) error {
return err1
})
Expand Down
9 changes: 9 additions & 0 deletions pool/result_context_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ func (p *ResultContextPool[T]) WithCancelOnError() *ResultContextPool[T] {
return p
}

// WithFailFast is an alias for the combination of WithFirstError and
// WithCancelOnError. By default, the errors from all tasks are returned and
// the pool's context is not canceled until the parent context is canceled.
func (p *ResultContextPool[T]) WithFailFast() *ResultContextPool[T] {
p.panicIfInitialized()
p.contextPool.WithFailFast()
return p
}

// WithMaxGoroutines limits the number of goroutines in a pool.
// Defaults to unlimited. Panics if n < 1.
func (p *ResultContextPool[T]) WithMaxGoroutines(n int) *ResultContextPool[T] {
Expand Down
16 changes: 16 additions & 0 deletions pool/result_context_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,22 @@ func TestResultContextPool(t *testing.T) {
require.ErrorIs(t, err, err1)
})

t.Run("WithFailFast", func(t *testing.T) {
t.Parallel()
p := NewWithResults[int]().WithContext(context.Background()).WithFailFast()
p.Go(func(ctx context.Context) (int, error) {
return 0, err1
})
p.Go(func(ctx context.Context) (int, error) {
<-ctx.Done()
return 1, ctx.Err()
})
results, err := p.Wait()
require.ErrorIs(t, err, err1)
require.NotErrorIs(t, err, context.Canceled)
require.Empty(t, results)
})

t.Run("WithCancelOnError and panic", func(t *testing.T) {
t.Parallel()
p := NewWithResults[int]().
Expand Down

0 comments on commit 995000d

Please sign in to comment.