|
|
||
|---|---|---|
| .. | ||
| group_test.go | ||
| group.go | ||
| limiter.go | ||
| README.md | ||
| result_test.go | ||
| result.go | ||
| stream_test.go | ||
| stream.go | ||
README
Background
This section offers some explanations below, but it's recommended to skip to the examples table below to get a feel for how this package works.
The main entrypoints to the package are the constructors:
group.New(): A simple Group, equivalent togo func() + wg.Add()/wg.Done()group.NewWithResults[T](): A group (ResultGroup) of tasks that returns resultsgroup.NewWithStreaming[T](): A group (StreamGroup) of tasks that stream their results (in order) with a callback
All of these group types share a set of configuration methods, but some configuration methods are only available for certain types. The following applies to all group types:
g.WithMaxConcurrent(n)returns a group configured to only run up tonconcurrent goroutines at a time.g.WithConcurrencyLimiter(l)returns a group configured to use the given limiter. This interface is implemented by the limiter in theinternal/mutablelimiterpackage.g.WithErrors()returns a group (Error(Result|Stream)?Group) which runs tasks that return an error.g.WithContext()returns a group (Context(Result|Stream)?Group) that runs tasks that require a context. It will use its context to unblock waiting on the limiter if the context is canceled.
The following is only available after g.WithErrors() or g.WithContext():
g.WithFirstError()configures the group to only hold on to the first error returned by a task. By default, it will return a combined error with every error returned by the task. This option is useful in case you don't really need a combined error with a million context errors.
The following is only available after g.WithContext():
g.WithCancelOnError()configures the group to cancel its context if a task returns an error.
This interface makes a few common problems more difficult to hit. Many of these are easy to catch and easy to fix, but if it's even better if they're not possible to hit in the first place. Some common issues this solves are:
- Returning early when a semaphore errors. This means we never clean up the started goroutines, so we return from the function with leaked goroutines.
- Forgetting a
wg.Add()orwg.Done()orwg.Wait()(although you still needg.Wait()) - Unintentionally canceling the context on error when using an
errgroup.Group - Unintentionally swallowing errors because
errgroup.Grouponly returns the first error - Forgetting mutexes when collecting results or errors
- Not adding a panic handler for goroutines, causing the whole process to crash if they panic (a future version may allow adding a custom panic handler)
Generics are only used where necessary, and the basic Group/ErrorGroup/ContextGroup avoids them entirely.
Usage examples
Without lib/group |
With lib/group |
|---|---|
|
|
|
|
|
|
|
|
|
A surprising amount of code that is difficult to understand and difficult to maintain. |
|