Skip to content

Commit 0a27cce

Browse files
committed
add yaml config for retry()
Signed-off-by: Sandor Szücs <[email protected]>
1 parent e0f2af0 commit 0a27cce

File tree

1 file changed

+71
-7
lines changed

1 file changed

+71
-7
lines changed

filters/retry/retry.go

+71-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,82 @@
11
package retry
22

33
import (
4+
"fmt"
5+
"net/http"
6+
47
"github.com/zalando/skipper/filters"
8+
"gopkg.in/yaml.v2"
9+
)
10+
11+
const (
12+
single = "single"
513
)
614

7-
type retry struct{}
15+
type (
16+
retrySpec struct{}
17+
RetryFilter struct {
18+
Type string `json:"type,omitempty"`
19+
StatusCodes []int `json:"status-codes,omitempty"`
20+
MaxTimes int `json:"max-times,omitempty"`
21+
22+
Check func(*http.Response) bool
23+
}
24+
)
825

926
// NewRetry creates a filter specification for the retry() filter
10-
func NewRetry() filters.Spec { return retry{} }
27+
func NewRetry() filters.Spec { return &retrySpec{} }
28+
29+
func (*retrySpec) Name() string { return filters.RetryName }
30+
31+
func (s *retrySpec) CreateFilter(args []interface{}) (filters.Filter, error) {
32+
rf := &RetryFilter{}
33+
34+
if config, ok := args[0].(string); !ok {
35+
return nil, fmt.Errorf("filter %q requires single string argument", s.Name())
36+
} else if err := yaml.Unmarshal([]byte(config), rf); err != nil {
37+
return nil, fmt.Errorf("failed to parse configuration: %w", err)
38+
}
39+
40+
switch rf.Type {
41+
case single:
42+
i := 0
43+
rf.Check = func(rsp *http.Response) bool {
44+
i++
45+
if i > rf.MaxTimes {
46+
return false
47+
}
48+
return shouldRetry(rsp.StatusCode, rf.StatusCodes)
49+
}
50+
}
51+
52+
return rf, nil
53+
}
54+
55+
// copy from proxy.shouldLog
56+
func shouldRetry(statusCode int, prefixes []int) bool {
57+
if len(prefixes) == 0 {
58+
return false
59+
}
60+
61+
match := false
62+
for _, prefix := range prefixes {
63+
switch {
64+
case prefix < 10:
65+
match = (statusCode >= prefix*100 && statusCode < (prefix+1)*100)
66+
case prefix < 100:
67+
match = (statusCode >= prefix*10 && statusCode < (prefix+1)*10)
68+
default:
69+
match = statusCode == prefix
70+
}
71+
if match {
72+
break
73+
}
74+
}
75+
return match
76+
}
1177

12-
func (retry) Name() string { return filters.RetryName }
13-
func (retry) CreateFilter([]interface{}) (filters.Filter, error) { return retry{}, nil }
14-
func (retry) Response(filters.FilterContext) {}
78+
func (rf *RetryFilter) Response(filters.FilterContext) {}
1579

16-
func (retry) Request(ctx filters.FilterContext) {
17-
ctx.StateBag()[filters.RetryName] = struct{}{}
80+
func (rf *RetryFilter) Request(ctx filters.FilterContext) {
81+
ctx.StateBag()[filters.RetryName] = rf.Check
1882
}

0 commit comments

Comments
 (0)