Browse Source

up: gracefully teardown when command ctx cancelled

Previously, if a long-lived plugin process (such as
an execution of `compose up`) was running and then
detached from a terminal, signalling the parent CLI
process to exit would leave the plugin process behind.

To address this, changes were introduced on the CLI side
(see: https://github.com/docker/cli/pull/4599) to enable
the CLI to notify a running plugin process that it should
exit. This makes it so that, when the parent CLI process
is going to exit, the command context of the plugin
command being executed is cancelled.

This commit takes advantage of these changes by tapping into
the command context's done channel and using it to teardown
on an up.

Signed-off-by: Laura Brehm <[email protected]>
Laura Brehm 1 year ago
parent
commit
dcbf005fe4
2 changed files with 21 additions and 19 deletions
  1. 1 6
      cmd/compose/compose.go
  2. 20 13
      pkg/compose/up.go

+ 1 - 6
cmd/compose/compose.go

@@ -278,12 +278,7 @@ const PluginName = "compose"
 
 // RunningAsStandalone detects when running as a standalone program
 func RunningAsStandalone() bool {
-	println("check running as standalone")
-	standalone := len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
-	fmt.Fprintf(os.Stderr, "%v+\n", os.Args)
-	println("len os.args", len(os.Args))
-	println("STANDALONE:", standalone)
-	return standalone
+	return len(os.Args) < 2 || os.Args[1] != manager.MetadataSubcommandName && os.Args[1] != PluginName
 }
 
 // RootCommand returns the compose command with its child commands

+ 20 - 13
pkg/compose/up.go

@@ -31,7 +31,7 @@ import (
 	"github.com/hashicorp/go-multierror"
 )
 
-func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error {
+func (s *composeService) Up(ctx context.Context, project *types.Project, options api.UpOptions) error { //nolint:gocyclo
 	err := progress.Run(ctx, tracing.SpanWrapFunc("project/up", tracing.ProjectOptions(project), func(ctx context.Context) error {
 		err := s.create(ctx, project, options.Create)
 		if err != nil {
@@ -69,24 +69,31 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 	doneCh := make(chan bool)
 	eg.Go(func() error {
 		first := true
+		gracefulTeardown := func() {
+			printer.Cancel()
+			fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
+			eg.Go(func() error {
+				err := s.Stop(context.Background(), project.Name, api.StopOptions{
+					Services: options.Create.Services,
+					Project:  project,
+				})
+				isTerminated = true
+				close(doneCh)
+				return err
+			})
+			first = false
+		}
 		for {
 			select {
 			case <-doneCh:
 				return nil
+			case <-ctx.Done():
+				if first {
+					gracefulTeardown()
+				}
 			case <-signalChan:
 				if first {
-					printer.Cancel()
-					fmt.Fprintln(s.stdinfo(), "Gracefully stopping... (press Ctrl+C again to force)")
-					eg.Go(func() error {
-						err := s.Stop(context.Background(), project.Name, api.StopOptions{
-							Services: options.Create.Services,
-							Project:  project,
-						})
-						isTerminated = true
-						close(doneCh)
-						return err
-					})
-					first = false
+					gracefulTeardown()
 				} else {
 					eg.Go(func() error {
 						return s.Kill(context.Background(), project.Name, api.KillOptions{