forked from motiv-labs/janus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
middleware.go
65 lines (54 loc) · 1.77 KB
/
middleware.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package retry
import (
"net/http"
"time"
"github.com/Knetic/govaluate"
"github.com/felixge/httpsnoop"
janusErr "github.com/hellofresh/janus/pkg/errors"
"github.com/hellofresh/janus/pkg/metrics"
"github.com/pkg/errors"
"github.com/rafaeljesus/retry-go"
log "github.com/sirupsen/logrus"
)
const (
defaultPredicate = "statusCode == 0 || statusCode >= 500"
proxySection = "proxy"
)
// NewRetryMiddleware creates a new retry middleware
func NewRetryMiddleware(cfg Config) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.WithFields(log.Fields{
"attempts": cfg.Attempts,
"backoff": cfg.Backoff,
}).Debug("Starting retry middleware")
if cfg.Predicate == "" {
cfg.Predicate = defaultPredicate
}
expression, err := govaluate.NewEvaluableExpression(cfg.Predicate)
if err != nil {
log.WithError(err).Error("could not create an expression with this predicate")
handler.ServeHTTP(w, r)
return
}
if err := retry.Do(func() error {
m := httpsnoop.CaptureMetrics(handler, w, r)
params := make(map[string]interface{}, 8)
params["statusCode"] = m.Code
params["request"] = r
result, err := expression.Evaluate(params)
if err != nil {
return errors.New("cannot evaluate the expression")
}
if result.(bool) {
return errors.Errorf("%s %s request failed", r.Method, r.URL)
}
return nil
}, cfg.Attempts, time.Duration(cfg.Backoff)); err != nil {
statsClient := metrics.WithContext(r.Context())
statsClient.SetHTTPRequestSection(proxySection).TrackRequest(r, nil, false).ResetHTTPRequestSection()
janusErr.Handler(w, r, errors.Wrap(err, "request failed too many times"))
}
})
}
}