Explorar el Código

Fix #11710: Avoid to try to close channel twice after hitting Ctrl-C on compose up (#11719)

Ensure done channel is closed only once

Signed-off-by: Jaime Soriano Pastor <[email protected]>
Jaime Soriano Pastor hace 1 año
padre
commit
5682480726
Se han modificado 1 ficheros con 13 adiciones y 13 borrados
  1. 13 13
      pkg/compose/up.go

+ 13 - 13
pkg/compose/up.go

@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
+	"sync/atomic"
 	"syscall"
 
 	"github.com/compose-spec/compose-go/v2/types"
@@ -65,9 +66,10 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 	// we might miss a signal while setting up the second channel read
 	// (this is also why signal.Notify is used vs signal.NotifyContext)
 	signalChan := make(chan os.Signal, 2)
-	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
 	defer close(signalChan)
-	var isTerminated bool
+	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
+	defer signal.Stop(signalChan)
+	var isTerminated atomic.Bool
 	printer := newLogPrinter(options.Start.Attach)
 
 	doneCh := make(chan bool)
@@ -78,12 +80,11 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 			formatter.ClearLine()
 			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{
+				err := s.Stop(context.WithoutCancel(ctx), project.Name, api.StopOptions{
 					Services: options.Create.Services,
 					Project:  project,
 				})
-				isTerminated = true
-				close(doneCh)
+				isTerminated.Store(true)
 				return err
 			})
 			first = false
@@ -120,7 +121,7 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 					break
 				}
 				eg.Go(func() error {
-					err := s.kill(context.Background(), project.Name, api.KillOptions{
+					err := s.kill(context.WithoutCancel(ctx), project.Name, api.KillOptions{
 						Services: options.Create.Services,
 						Project:  project,
 						All:      true,
@@ -165,18 +166,17 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 		})
 	}
 
-	// We don't use parent (cancelable) context as we manage sigterm to stop the stack
-	err = s.start(context.Background(), project.Name, options.Start, printer.HandleEvent)
-	if err != nil && !isTerminated { // Ignore error if the process is terminated
+	// We use the parent context without cancelation as we manage sigterm to stop the stack
+	err = s.start(context.WithoutCancel(ctx), project.Name, options.Start, printer.HandleEvent)
+	if err != nil && !isTerminated.Load() { // Ignore error if the process is terminated
 		return err
 	}
 
+	// Signal for the signal-handler goroutines to stop
+	close(doneCh)
+
 	printer.Stop()
 
-	if !isTerminated {
-		// signal for the signal-handler goroutines to stop
-		close(doneCh)
-	}
 	err = eg.Wait().ErrorOrNil()
 	if exitCode != 0 {
 		errMsg := ""