From a275947784ed0772b08bbd43114c5cc0a1ba8feb Mon Sep 17 00:00:00 2001 From: DCCooper <1866858@gmail.com> Date: Tue, 15 Sep 2020 19:42:14 +0800 Subject: [PATCH] bugfix: fix build hang problem when error happened before pipe open Signed-off-by: DCCooper <1866858@gmail.com> --- builder/builder.go | 2 +- builder/dockerfile/builder.go | 3 ++- cmd/cli/build.go | 4 +++- daemon/build.go | 8 +++++++- daemon/status.go | 6 ++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/builder/builder.go b/builder/builder.go index 02c40ea7..1f650a5c 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -29,7 +29,7 @@ import ( // Builder is an interface for building an image type Builder interface { - Build() (imageID string, err error) + Build(chan struct{}) (imageID string, err error) StatusChan() <-chan string CleanResources() error OutputPipeWrapper() *exporter.PipeWrapper diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index 27c688f9..fd0bd695 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -407,7 +407,7 @@ func getFlagsAndArgs(line *parser.Line, allowFlags map[string]bool) (map[string] } // Build makes the image -func (b *Builder) Build() (string, error) { +func (b *Builder) Build(syncChan chan struct{}) (string, error) { var ( executeTimer = b.cliLog.StartTimer("\nTotal") err error @@ -446,6 +446,7 @@ func (b *Builder) Build() (string, error) { } } + close(syncChan) // 4. export images if err = b.export(imageID); err != nil { return "", errors.Wrapf(err, "exporting images failed") diff --git a/cmd/cli/build.go b/cmd/cli/build.go index 08c591b5..5c94bedd 100644 --- a/cmd/cli/build.go +++ b/cmd/cli/build.go @@ -150,7 +150,9 @@ func buildCommand(c *cobra.Command, args []string) error { logrus.Debugf("Status get failed: %v", err2) cancel() } - return errors.Wrap(err2, "error runStatus") + // user should not pay attention on runStatus error + // the errors were already printed to daemon log if any + return nil }) return eg.Wait() diff --git a/daemon/build.go b/daemon/build.go index b66a9058..6c5e0acb 100644 --- a/daemon/build.go +++ b/daemon/build.go @@ -59,11 +59,12 @@ func (b *Backend) Build(req *pb.BuildRequest, stream pb.Control_BuildServer) err pipeWrapper := builder.OutputPipeWrapper() eg, ctx := errgroup.WithContext(ctx) + syncPipeChan := make(chan struct{}) eg.Go(func() error { b.syncBuildStatus(req.BuildID) <- struct{}{} b.closeStatusChan(req.BuildID) var berr error - imageID, berr = builder.Build() + imageID, berr = builder.Build(syncPipeChan) if berr != nil && pipeWrapper != nil { // in case there is error during Build stage, the backend will always waiting for content write into @@ -85,6 +86,11 @@ func (b *Backend) Build(req *pb.BuildRequest, stream pb.Control_BuildServer) err if pipeWrapper == nil { return nil } + select { + case <-syncPipeChan: + case <-ctx.Done(): + return nil + } f, perr := exporter.PipeArchiveStream(pipeWrapper) if perr != nil { return perr diff --git a/daemon/status.go b/daemon/status.go index c08a6e77..d8b666ee 100644 --- a/daemon/status.go +++ b/daemon/status.go @@ -41,10 +41,16 @@ func (b *Backend) Status(req *pb.StatusRequest, stream pb.Control_StatusServer) builder, err := b.daemon.Builder(req.BuildID) if err != nil { + logrus.WithFields(logrus.Fields{ + "BuildID": req.GetBuildID(), + }).Error(err) return err } for value := range builder.StatusChan() { if err := stream.Send(&pb.StatusResponse{Content: value}); err != nil { + logrus.WithFields(logrus.Fields{ + "BuildID": req.GetBuildID(), + }).Error(err) return err } } -- 2.19.1