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

