| ▲ | evanelias 2 days ago |
| You can just use golang.org/x/sync/errgroup instead, which has always provided this style of use. errgroup also has other niceties like error propagation, context cancellation, and concurrency limiting. |
|
| ▲ | Cyph0n 2 days ago | parent | next [-] |
| Context cancellation is not always desirable. I personally have been bitten multiple times by the default behavior of errgroup. |
| |
| ▲ | CamouflagedKiwi 2 days ago | parent [-] | | You have to explicitly propagate the group's context if you want it to cancel. You can just not do that if you don't want - there certainly are cases for that. | | |
| ▲ | Cyph0n a day ago | parent [-] | | But if you’re looking at the package API, there is no alternative constructor for Group, which makes it seem as if the most common default is to construct a Group using WithContext. Also, 2/3 of the examples use WithContext. My recommendation would be to have a NewGroup function or equivalent that returns an empty group to surface it as an alternative to WithContext. | | |
| ▲ | evanelias a day ago | parent [-] | | > My recommendation would be to have a NewGroup function or equivalent that returns an empty group That goes against common practices in Golang, articulated in the second paragraph of https://go.dev/doc/effective_go#allocation_new among many other places. Also the errgroup documentation specifically says "A zero Group is valid, has no limit on the number of active goroutines, and does not cancel on error." And, as you noted, one of the examples doesn't use WithContext. | | |
| ▲ | Cyph0n a day ago | parent [-] | | That’s one of my Go pet peeves - zero/default structs are sometimes valid and sometimes not, and the only way to know is to dig into the docs. I prefer the API to speak for itself, ideally enforced by the language/compiler. |
|
|
|
|
|
| ▲ | porridgeraisin 2 days ago | parent | prev [-] |
| errgroup cancels the whole task if even one subtask fails however. That is not desirable always. |
| |
| ▲ | Groxx 2 days ago | parent | next [-] | | It does not, which is easy to verify from the source. Every func passed in is always run (with the exception of TryGo which is explicitly "maybe"). At best, using the optional, higher-effort errgroup.WithContext will cancel the context but still run all of your funcs. If you don't want that for one of the funcs, or some component of them, just don't use the context. | |
| ▲ | evanelias 2 days ago | parent | prev [-] | | If the context cancellation is undesirable, you just choose not to use WithContext, as the sibling comment mentions. You could also just make your subtask function return nil always, if you just want to get the automatic bookkeeping call pattern (like WaitGroup.Go from Golang 1.25), plus optional concurrency limiting. Also note, even if a subtask function returns an error, the errgroup Wait blocking semantics are identical to those of a WaitGroup. Wait will return the first error when it returns, but it doesn't unblock early on first error. |
|