From 93dd1a45584d9e114cc9ff1cdf09067b45732275 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 22 Aug 2025 15:56:19 +0200 Subject: [PATCH] internal/sync: replace go-multierror.Group with golang.org/x/sync/errgroup The go-multierror Group is just a shallow wrapper around sync.WaitGroup; https://github.com/hashicorp/go-multierror/blob/v1.1.1/group.go#L5-L38 It does not limit concurrency, but handles synchronisation to collect all errors (if any) in a go-multierror. This patch replaces the go-multierror.Group for a sync.ErrGroup (which is slightly easier to use, and does allow for limiting concurrency if wanted), and a basic slice with mutex to collect the errors and to produce a stdlib multi-error through errors.Join Signed-off-by: Sebastiaan van Stijn --- internal/sync/tar.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/internal/sync/tar.go b/internal/sync/tar.go index 1abec82db..4250b6afc 100644 --- a/internal/sync/tar.go +++ b/internal/sync/tar.go @@ -29,11 +29,11 @@ import ( "path" "path/filepath" "strings" - - "github.com/hashicorp/go-multierror" + "sync" "github.com/docker/docker/api/types/container" "github.com/moby/go-archive" + "golang.org/x/sync/errgroup" ) type archiveEntry struct { @@ -84,7 +84,14 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er if len(pathsToDelete) != 0 { deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...) } - var eg multierror.Group + + var ( + eg errgroup.Group + errMu sync.Mutex + errs = make([]error, 0, len(containers)*2) // max 2 errs per container + ) + + eg.SetLimit(16) // arbitrary limit, adjust to taste :D for i := range containers { containerID := containers[i].ID tarReader := tarArchive(pathsToCopy) @@ -92,17 +99,23 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er eg.Go(func() error { if len(deleteCmd) != 0 { if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil { - return fmt.Errorf("deleting paths in %s: %w", containerID, err) + errMu.Lock() + errs = append(errs, fmt.Errorf("deleting paths in %s: %w", containerID, err)) + errMu.Unlock() } } if err := t.client.Untar(ctx, containerID, tarReader); err != nil { - return fmt.Errorf("copying files to %s: %w", containerID, err) + errMu.Lock() + errs = append(errs, fmt.Errorf("copying files to %s: %w", containerID, err)) + errMu.Unlock() } - return nil + return nil // don't fail-fast; collect all errors }) } - return eg.Wait().ErrorOrNil() + + _ = eg.Wait() + return errors.Join(errs...) } type ArchiveBuilder struct {