github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/exec/retry_error_step.go (about)

     1  package exec
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"net/url"
     9  	"reflect"
    10  	"regexp"
    11  
    12  	"code.cloudfoundry.org/lager"
    13  	"code.cloudfoundry.org/lager/lagerctx"
    14  	"github.com/pf-qiu/concourse/v6/atc/worker/transport"
    15  )
    16  
    17  type Retriable struct {
    18  	Cause error
    19  }
    20  
    21  func (r Retriable) Error() string {
    22  	return fmt.Sprintf("retriable: %s", r.Cause.Error())
    23  }
    24  
    25  type RetryErrorStep struct {
    26  	Step
    27  
    28  	delegateFactory BuildStepDelegateFactory
    29  }
    30  
    31  func RetryError(step Step, delegateFactory BuildStepDelegateFactory) Step {
    32  	return RetryErrorStep{
    33  		Step:            step,
    34  		delegateFactory: delegateFactory,
    35  	}
    36  }
    37  
    38  func (step RetryErrorStep) Run(ctx context.Context, state RunState) (bool, error) {
    39  	logger := lagerctx.FromContext(ctx)
    40  	runOk, runErr := step.Step.Run(ctx, state)
    41  
    42  	// If the build has been aborted, then no need to retry.
    43  	select {
    44  	case <-ctx.Done():
    45  		return runOk, runErr
    46  	default:
    47  	}
    48  
    49  	if runErr != nil && step.toRetry(logger, runErr) {
    50  		logger.Info("retriable", lager.Data{"error": runErr.Error()})
    51  		delegate := step.delegateFactory.BuildStepDelegate(state)
    52  		delegate.Errored(logger, fmt.Sprintf("%s, will retry ...", runErr.Error()))
    53  		runErr = Retriable{runErr}
    54  	}
    55  	return runOk, runErr
    56  }
    57  
    58  func (step RetryErrorStep) toRetry(logger lager.Logger, err error) bool {
    59  	var urlError *url.Error
    60  	var netError net.Error
    61  	if errors.As(err, &transport.WorkerMissingError{}) || errors.As(err, &transport.WorkerUnreachableError{}) || errors.As(err, &urlError) {
    62  		logger.Debug("retry-error",
    63  			lager.Data{"err_type": reflect.TypeOf(err).String(), "err": err.Error()})
    64  		return true
    65  	} else if errors.As(err, &netError) || regexp.MustCompile(`worker .+ disappeared`).MatchString(err.Error()) {
    66  		logger.Debug("retry-error",
    67  			lager.Data{"err_type": reflect.TypeOf(err).String(), "err": err})
    68  		return true
    69  	}
    70  	return false
    71  }