From 210d1acba11aee0cb4a543fa97feb9ecfc4ba532 Mon Sep 17 00:00:00 2001 From: chenjiankun Date: Tue, 15 Jun 2021 20:51:10 +0800 Subject: [PATCH] docker: fix ProcessEvent block when CloseStreams block The ProcessEvent function will block if the CloseStreams function block in exit event processing. The reason is the ProcessEvent function is serial processing. So we need add a timeout mechanism to deal with it. --- components/engine/container/stream/streams.go | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/components/engine/container/stream/streams.go b/components/engine/container/stream/streams.go index 585f9e8e3..1a7ef33d4 100644 --- a/components/engine/container/stream/streams.go +++ b/components/engine/container/stream/streams.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "strings" "sync" + "time" "github.com/containerd/containerd/cio" "github.com/docker/docker/pkg/broadcaster" @@ -92,27 +93,38 @@ func (c *Config) NewNopInputPipe() { // CloseStreams ensures that the configured streams are properly closed. func (c *Config) CloseStreams() error { - var errors []string + done := make(chan struct{}) + var errorsInLine error - if c.stdin != nil { - if err := c.stdin.Close(); err != nil { - errors = append(errors, fmt.Sprintf("error close stdin: %s", err)) + go func() { + var errors []string + if c.stdin != nil { + if err := c.stdin.Close(); err != nil { + errors = append(errors, fmt.Sprintf("error close stdin: %s", err)) + } } - } - if err := c.stdout.Clean(); err != nil { - errors = append(errors, fmt.Sprintf("error close stdout: %s", err)) - } + if err := c.stdout.Clean(); err != nil { + errors = append(errors, fmt.Sprintf("error close stdout: %s", err)) + } - if err := c.stderr.Clean(); err != nil { - errors = append(errors, fmt.Sprintf("error close stderr: %s", err)) - } + if err := c.stderr.Clean(); err != nil { + errors = append(errors, fmt.Sprintf("error close stderr: %s", err)) + } - if len(errors) > 0 { - return fmt.Errorf(strings.Join(errors, "\n")) - } + if len(errors) > 0 { + errorsInLine = fmt.Errorf(strings.Join(errors, "\n")) + } + + close(done) + }() - return nil + select { + case <-done: + return errorsInLine + case <-time.After(3 * time.Second): + return fmt.Errorf("close stream timeout") + } } // CopyToPipe connects streamconfig with a libcontainerd.IOPipe -- 2.27.0