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 {