build: parallelize forced reference evaluation
Use an errgroup helper to evaluate result refs concurrently during forced evaluation, and fail fast on the first evaluation error. This mitigates current case in bake where chained targets with a multi-platform build could miss secrets and other session properties. The outline for the issue case: - Base target is solved but only lazily and not really loaded/tracked in build graph yet. - Child targets are loaded, base target waits. - Evaluate is called for base stage (because it might be missing result condition), child stage is processed as build result. This happens in parallel. - Because `Evaluate()` was called synchronously, it may have not been called yet for the second platform while the child target already needs to run `RUN --mount=type=secret`. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
+19
-1
@@ -630,7 +630,7 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
|
||||
return nil, err
|
||||
}
|
||||
} else if forceEval {
|
||||
if err := res.EachRef(func(ref gateway.Reference) error {
|
||||
if err := eachRefParallel(ctx, res, func(ctx context.Context, ref gateway.Reference) error {
|
||||
return ref.Evaluate(ctx)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
@@ -1321,6 +1321,24 @@ func solve(ctx context.Context, c gateway.Client, req gateway.SolveRequest) (*ga
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func eachRefParallel(ctx context.Context, res *gateway.Result, fn func(context.Context, gateway.Reference) error) error {
|
||||
var refs []gateway.Reference
|
||||
if err := res.EachRef(func(ref gateway.Reference) error {
|
||||
refs = append(refs, ref)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
for _, ref := range refs {
|
||||
eg.Go(func() error {
|
||||
return fn(ctx, ref)
|
||||
})
|
||||
}
|
||||
return eg.Wait()
|
||||
}
|
||||
|
||||
func catchFrontendError(retErr, frontendErr *error) {
|
||||
*frontendErr = *retErr
|
||||
if errors.Is(*retErr, ErrRestart) {
|
||||
|
||||
Reference in New Issue
Block a user