Repository: traefik/traefik
File: pkg/middlewares/retry/retry.go (Go)

Code before:
	name     string
}

// New returns a new retry middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Retry, listener Listener, name string) (http.Handler, error) {
	log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")

	if config.Attempts <= 0 {
		return nil, fmt.Errorf("incorrect (or empty) value for attempt (%d)", config.Attempts)
	}

	return &retry{
		attempts: config.Attempts,
		next:     next,
		listener: listener,
		name:     name,
	}, nil
}

func (r *retry) GetTracingInformation() (string, ext.SpanKindEnum) {
	return r.name, tracing.SpanKindNoneEnum
}

func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// if we might make multiple attempts, swap the body for an ioutil.NopCloser
	// cf https://github.com/traefik/traefik/issues/1008
	if r.attempts > 1 {
		body := req.Body
		defer body.Close()
		req.Body = ioutil.NopCloser(body)
	}

	attempts := 1
	for {
		shouldRetry := attempts < r.attempts
		retryResponseWriter := newResponseWriter(rw, shouldRetry)

		// Disable retries when the backend already received request data
		trace := &httptrace.ClientTrace{
			WroteHeaders: func() {
				retryResponseWriter.DisableRetries()
			},
			WroteRequest: func(httptrace.WroteRequestInfo) {
				retryResponseWriter.DisableRetries()
			},
		}
		newCtx := httptrace.WithClientTrace(req.Context(), trace)

		r.next.ServeHTTP(retryResponseWriter, req.WithContext(newCtx))

		if !retryResponseWriter.ShouldRetry() {

Review comment (suggestion):
I think it's more idiomatic to remove the `new` and to return the following:

```suggestion
			return &bo.ZeroBackOff{}
```

Code after:
	NextBackOff() time.Duration
}

// retry is a middleware that retries requests.
type retry struct {
	attempts        int
	initialInterval time.Duration
	next            http.Handler
	listener        Listener
	name            string
}

// New returns a new retry middleware.
func New(ctx context.Context, next http.Handler, config dynamic.Retry, listener Listener, name string) (http.Handler, error) {
	log.FromContext(middlewares.GetLoggerCtx(ctx, name, typeName)).Debug("Creating middleware")

	if config.Attempts <= 0 {
		return nil, fmt.Errorf("incorrect (or empty) value for attempt (%d)", config.Attempts)
	}

	return &retry{
		attempts:        config.Attempts,
		initialInterval: time.Duration(config.InitialInterval),
		next:            next,
		listener:        listener,
		name:            name,
	}, nil
}

func (r *retry) GetTracingInformation() (string, ext.SpanKindEnum) {
	return r.name, tracing.SpanKindNoneEnum
}

func (r *retry) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// if we might make multiple attempts, swap the body for an ioutil.NopCloser
	// cf https://github.com/traefik/traefik/issues/1008
	if r.attempts > 1 {
		body := req.Body
		defer body.Close()
		req.Body = ioutil.NopCloser(body)
	}

	attempts := 1
	backOff := r.newBackOff()
	currentInterval := 0 * time.Millisecond
	for {
		select {
		case <-time.After(currentInterval):

			shouldRetry := attempts < r.attempts
			retryResponseWriter := newResponseWriter(rw, shouldRetry)