diff --git a/cmd/docker/docker.go b/cmd/docker/docker.go index 3cf0ba966f..65f7499d75 100644 --- a/cmd/docker/docker.go +++ b/cmd/docker/docker.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "io" "os" "os/exec" "os/signal" @@ -325,6 +326,25 @@ func tryPluginRun(ctx context.Context, dockerCli command.Cli, cmd *cobra.Command return nil } +// registerForceExitGoroutine registers a goroutine that will force exit the +// process after 3 SIGTERM/SIGINT signals. +func registerForceExitGoroutine(ctx context.Context, w io.Writer) { + // setup a signal handler to force exit after 3 SIGTERM/SIGINT + go func() { + <-ctx.Done() + sig := make(chan os.Signal, 2) + signal.Notify(sig, platformsignals.TerminationSignals...) + count := 0 + for range sig { + count++ + if count >= 2 { + _, _ = fmt.Fprint(w, "\ngot 3 SIGTERM/SIGINTs, forcefully exiting\n") + os.Exit(1) + } + } + }() +} + //nolint:gocyclo func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { tcmd := newDockerCommand(dockerCli) @@ -384,6 +404,10 @@ func runDocker(ctx context.Context, dockerCli *command.DockerCli) error { } } + // This is a fallback for the case where the command does not exit + // based on context cancellation. + registerForceExitGoroutine(ctx, dockerCli.Err()) + // We've parsed global args already, so reset args to those // which remain. cmd.SetArgs(args)