diff --git a/pkg/lifecycle/binary.go b/pkg/lifecycle/binary.go index 8e15070847..e4f7ef2980 100644 --- a/pkg/lifecycle/binary.go +++ b/pkg/lifecycle/binary.go @@ -15,6 +15,7 @@ package lifecycle import ( + "context" "fmt" "io" "net/http" @@ -26,8 +27,12 @@ import ( "time" "go.uber.org/zap" + + "github.com/pipe-cd/pipecd/pkg/backoff" ) +const runBinaryRetryCount = 3 + type Command struct { cmd *exec.Cmd stoppedCh chan struct{} @@ -66,27 +71,35 @@ func (c *Command) GracefulStop(period time.Duration) error { } func RunBinary(execPath string, args []string) (*Command, error) { - cmd := exec.Command(execPath, args...) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd, err := backoff.NewRetry(runBinaryRetryCount, backoff.NewConstant(5*time.Second)).Do(context.Background(), func() (interface{}, error) { + cmd := exec.Command(execPath, args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + if err := cmd.Start(); err != nil { + return nil, err + } - if err := cmd.Start(); err != nil { - return nil, err - } + c := &Command{ + cmd: cmd, + stoppedCh: make(chan struct{}), + result: atomic.Pointer[error]{}, + } + go func() { + err := cmd.Wait() + c.result.Store(&err) + close(c.stoppedCh) + }() + + return c, nil + }) - c := &Command{ - cmd: cmd, - stoppedCh: make(chan struct{}), - result: atomic.Pointer[error]{}, + if err != nil { + return nil, err } - go func() { - err := cmd.Wait() - c.result.Store(&err) - close(c.stoppedCh) - }() - return c, nil + return cmd.(*Command), nil // The return type is always *Command. } // DownloadBinary downloads a file from the given URL into the specified path