ソースを参照

Handle errors and allow to send multiple kills if one failed

Signed-off-by: Jaime Soriano Pastor <[email protected]>
Jaime Soriano Pastor 1 年間 前
コミット
6a3501f901
1 ファイル変更25 行追加12 行削除
  1. 25 12
      pkg/compose/up.go

+ 25 - 12
pkg/compose/up.go

@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
+	"sync/atomic"
 	"syscall"
 
 	"github.com/compose-spec/compose-go/v2/types"
@@ -29,6 +30,7 @@ import (
 	"github.com/docker/compose/v2/internal/tracing"
 	"github.com/docker/compose/v2/pkg/api"
 	"github.com/docker/compose/v2/pkg/progress"
+	"github.com/docker/docker/errdefs"
 	"github.com/eiannone/keyboard"
 	"github.com/hashicorp/go-multierror"
 	"github.com/sirupsen/logrus"
@@ -106,6 +108,9 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 				}
 			}
 		}
+
+		// killRunning is used to control that we don't run more than one kill if signals are spammed.
+		var killRunning atomic.Bool
 		for {
 			select {
 			case <-doneCh:
@@ -117,19 +122,27 @@ func (s *composeService) Up(ctx context.Context, project *types.Project, options
 			case <-signalChan:
 				if first {
 					gracefulTeardown()
-				} else {
-					eg.Go(func() error {
-						// Intentionally ignore errors, for cases where some
-						// of the containers are already stopped.
-						s.kill(context.Background(), project.Name, api.KillOptions{
-							Services: options.Create.Services,
-							Project:  project,
-							All:      true,
-						})
-						return nil
-					})
-					return nil
+					break
+				}
+				if !killRunning.CompareAndSwap(false, true) {
+					break
 				}
+				eg.Go(func() error {
+					defer killRunning.Store(false)
+					// Intentionally ignore errors, for cases where some
+					// of the containers are already stopped.
+					err := s.kill(context.Background(), project.Name, api.KillOptions{
+						Services: options.Create.Services,
+						Project:  project,
+						All:      true,
+					})
+					// Ignore errors indicating that some of the containers were already stopped or removed.
+					if errdefs.IsNotFound(err) || errdefs.IsConflict(err) {
+						return nil
+					}
+
+					return err
+				})
 			case event := <-kEvents:
 				formatter.KeyboardManager.HandleKeyEvents(event, ctx, project, options)
 			}