diff --git a/concurrency/join.go b/concurrency/join.go new file mode 100644 index 0000000..e18babd --- /dev/null +++ b/concurrency/join.go @@ -0,0 +1,39 @@ +/* +Copyright 2025 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package concurrency + +import ( + "context" + "errors" + "sync" +) + +// Join runs multiple Runners concurrently and waits for all of them to +// complete. It returns a combined error if any of the Runners return an error. +// It does not cancel the context if one of the Runners fails; all Runners are +// allowed to complete. +func Join(ctx context.Context, runners ...Runner) error { + errs := make([]error, len(runners)) + var wg sync.WaitGroup + wg.Add(len(runners)) + for i := range runners { + go func(i int) { + errs[i] = runners[i](ctx) + wg.Done() + }(i) + } + wg.Wait() + + return errors.Join(errs...) +}