github.com/ava-labs/avalanchego@v1.11.11/vms/rpcchainvm/runtime/subprocess/linux_stopper.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  //go:build linux
     5  // +build linux
     6  
     7  // ^ SIGTERM signal is not available on Windows
     8  // ^ syscall.SysProcAttr only has field Pdeathsig on Linux
     9  
    10  package subprocess
    11  
    12  import (
    13  	"context"
    14  	"os/exec"
    15  	"syscall"
    16  
    17  	"go.uber.org/zap"
    18  
    19  	"github.com/ava-labs/avalanchego/utils/logging"
    20  	"github.com/ava-labs/avalanchego/utils/wrappers"
    21  	"github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime"
    22  )
    23  
    24  func NewCmd(path string, args ...string) *exec.Cmd {
    25  	cmd := exec.Command(path, args...)
    26  	cmd.SysProcAttr = &syscall.SysProcAttr{Pdeathsig: syscall.SIGTERM}
    27  	return cmd
    28  }
    29  
    30  func stop(ctx context.Context, log logging.Logger, cmd *exec.Cmd) {
    31  	waitChan := make(chan error)
    32  	go func() {
    33  		// attempt graceful shutdown
    34  		errs := wrappers.Errs{}
    35  		err := cmd.Process.Signal(syscall.SIGTERM)
    36  		errs.Add(err)
    37  		_, err = cmd.Process.Wait()
    38  		errs.Add(err)
    39  		waitChan <- errs.Err
    40  		close(waitChan)
    41  	}()
    42  
    43  	ctx, cancel := context.WithTimeout(ctx, runtime.DefaultGracefulTimeout)
    44  	defer cancel()
    45  
    46  	select {
    47  	case err := <-waitChan:
    48  		if err == nil {
    49  			log.Debug("subprocess gracefully shutdown")
    50  		} else {
    51  			log.Error("subprocess graceful shutdown failed",
    52  				zap.Error(err),
    53  			)
    54  		}
    55  	case <-ctx.Done():
    56  		// force kill
    57  		err := cmd.Process.Kill()
    58  		log.Error("subprocess was killed",
    59  			zap.Error(err),
    60  		)
    61  	}
    62  }