build: create error group per opt

Using the syncronization primitive, we can avoid needing to create a
separate wait group.

This allows us to sidestep the issue where the wait group could be
completed, but the build invocation functions had not terminated - if
one of the functions was to terminate with an error, then it was
possible to encounter a race condition, where the result handling code
would begin executing, despite an error.

The refactor to use a separate error group which more elegantly handles
the concept of function returns and errors, ensures that we can't
encounter this issue.

Signed-off-by: Justin Chadwell <me@jedevc.com>
(cherry picked from commit 8b7aa1a168)
pull/1556/head
Justin Chadwell 2 years ago committed by CrazyMax
parent 65cea456fd
commit 2bb8ce2f57
No known key found for this signature in database
GPG Key ID: 3248E46B6BB8C7F7

@ -952,10 +952,10 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
if multiTarget { if multiTarget {
span, ctx = tracing.StartSpan(ctx, k) span, ctx = tracing.StartSpan(ctx, k)
} }
baseCtx := ctx
res := make([]*client.SolveResponse, len(dps)) res := make([]*client.SolveResponse, len(dps))
wg := &sync.WaitGroup{} eg2, ctx := errgroup.WithContext(ctx)
wg.Add(len(dps))
var pushNames string var pushNames string
var insecurePush bool var insecurePush bool
@ -993,9 +993,8 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
pw := progress.WithPrefix(w, k, multiTarget) pw := progress.WithPrefix(w, k, multiTarget)
c := clients[dp.driverIndex] c := clients[dp.driverIndex]
eg.Go(func() error { eg2.Go(func() error {
pw = progress.ResetTime(pw) pw = progress.ResetTime(pw)
defer wg.Done()
if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil { if err := waitContextDeps(ctx, dp.driverIndex, results, &so); err != nil {
return err return err
@ -1128,17 +1127,15 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opt map[s
} }
eg.Go(func() (err error) { eg.Go(func() (err error) {
ctx := baseCtx
defer func() { defer func() {
if span != nil { if span != nil {
tracing.FinishWithError(span, err) tracing.FinishWithError(span, err)
} }
}() }()
pw := progress.WithPrefix(w, "default", false) pw := progress.WithPrefix(w, "default", false)
wg.Wait() if err := eg2.Wait(); err != nil {
select { return err
case <-ctx.Done():
return ctx.Err()
default:
} }
respMu.Lock() respMu.Lock()

Loading…
Cancel
Save