Skip to content

build: change build handler to evaluate instead of onresult #3224

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jsternberg
Copy link
Collaborator

This changes the build handler to customize the behavior of evaluate
rather than onresult and also simplifies the ResultHandle. The
ResultHandle is now only valid within the gateway callback and can be
used to start containers from the handler.

Evaluate now executes inside of the gateway callback rather than
having a separate implementation that executes or re-invokes the build.
This keeps the gateway callback session open until the debugger has
returned.

The ErrReload for monitor has now been moved into the build package
and been renamed to ErrRestart. This is because it restarts the build
so the name makes a bit more sense. The actual use of this functionality
is still tied to the monitor reload.

Copy link
Member

@tonistiigi tonistiigi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(buildx) reload
[+] Building 0.0s (0/1)                                                                                                                                            
panic: send on closed channel

goroutine 188 [running]:
github.com/docker/buildx/util/progress.(*Printer).Write(0x14000067580, 0x140007f5440)
	github.com/docker/buildx/util/progress/printer.go:67 +0x2c
github.com/docker/buildx/util/progress.(*prefixed).Write(0x1d2a8112?, 0xedfd53156?)
	github.com/docker/buildx/util/progress/multiwriter.go:32 +0x54
github.com/docker/buildx/util/progress.(*pw).Write(0x14000746d40, 0x140007f5380)
	github.com/docker/buildx/util/progress/reset.go:66 +0xa0
github.com/docker/buildx/util/progress.NewChannel.func1()
	github.com/docker/buildx/util/progress/writer.go:73 +0x50
created by github.com/docker/buildx/util/progress.NewChannel in goroutine 186
	github.com/docker/buildx/util/progress/writer.go:54 +0xb0

@jsternberg jsternberg force-pushed the evaluate-handler branch 3 times, most recently from 9bbac00 to e8f1e3c Compare June 6, 2025 19:16
@tonistiigi tonistiigi added this to the v0.25.0 milestone Jun 9, 2025
@jsternberg jsternberg force-pushed the evaluate-handler branch 5 times, most recently from d9c4d23 to a0d2017 Compare June 9, 2025 18:00
@jsternberg
Copy link
Collaborator Author

Added an additional commit to refactor the pause/unpause functionality for the printer. It seems the new evaluation method is causing some conflicts because it's possible for statuses to be sent while the printer is paused. This change should make that more reliable.

@jsternberg jsternberg requested a review from tonistiigi June 9, 2025 18:21
@@ -504,24 +507,28 @@ func BuildWithResultHandler(ctx context.Context, nodes []builder.Node, opts map[
results.Set(rKey, res)

if children := childTargets[rKey]; len(children) > 0 {
if err := waitForChildren(ctx, res, results, children); err != nil {
if err := waitForChildren(ctx, bh, c, res, results, children); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this connected to waitForChildren. Wouldn't it make more sense to have errgroup with one part going to waitForChildren and other to eval callback. Or can't the hook just run before?

return nil, err
}
} else if bh != nil && bh.Evaluate != nil {
if err := bh.Evaluate(ctx, c, res); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case of ErrRestart shouldn't we return canceled from the callback. Or maybe canceled wrapped with "build restarted by client".

OnResult: func(driverIndex int, gotRes *build.ResultHandle) {
m.mu.Lock()
defer m.mu.Unlock()
Evaluate: func(ctx context.Context, c gateway.Client, res *gateway.Result) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this doesn't use any local variables in the closure, move this to actual private method. Or you can just add Evaluate to Monitor and pass it as handler.

This changes the progress printer's pause and unpause implementation to
be reentrant to prevent race conditions and it also allows the status
updates to be buffered when the display is paused.

The previous implementation mixed the pause implementation with the
finish implementation and could cause a send on closed channel panic
because it could close the status channel before it had finished being
used. Now, the status channel is not closed.

When the display is enabled, the status channel will be forwarded to an
internal channel that is used to display the updates. When the display
is paused, the status channel will have the statuses buffered in memory
to be sent when the progress display is resumed.

The `Unpause` method has also been renamed to `Resume`.

Signed-off-by: Jonathan A. Sternberg <[email protected]>
@jsternberg jsternberg force-pushed the evaluate-handler branch 3 times, most recently from fbce087 to 9cbee6a Compare June 9, 2025 19:27
This changes the build handler to customize the behavior of evaluate
rather than onresult and also simplifies the `ResultHandle`. The
`ResultHandle` is now only valid within the gateway callback and can be
used to start containers from the handler.

`Evaluate` now executes inside of the gateway callback rather than
having a separate implementation that executes or re-invokes the build.
This keeps the gateway callback session open until the debugger has
returned.

The `ErrReload` for monitor has now been moved into the `build` package
and been renamed to `ErrRestart`. This is because it restarts the build
so the name makes a bit more sense. The actual use of this functionality
is still tied to the monitor reload.

Signed-off-by: Jonathan A. Sternberg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants