|  | @@ -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 := ""
 |