Skip to content

Commit

Permalink
add yaml config for retry()
Browse files Browse the repository at this point in the history
Signed-off-by: Sandor Szücs <[email protected]>
  • Loading branch information
szuecs committed Aug 19, 2024
1 parent e0f2af0 commit 0a27cce
Showing 1 changed file with 71 additions and 7 deletions.
78 changes: 71 additions & 7 deletions filters/retry/retry.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,82 @@
package retry

import (
"fmt"
"net/http"

"github.com/zalando/skipper/filters"
"gopkg.in/yaml.v2"
)

const (
single = "single"
)

type retry struct{}
type (
retrySpec struct{}
RetryFilter struct {
Type string `json:"type,omitempty"`
StatusCodes []int `json:"status-codes,omitempty"`
MaxTimes int `json:"max-times,omitempty"`

Check func(*http.Response) bool
}
)

// NewRetry creates a filter specification for the retry() filter
func NewRetry() filters.Spec { return retry{} }
func NewRetry() filters.Spec { return &retrySpec{} }

func (*retrySpec) Name() string { return filters.RetryName }

func (s *retrySpec) CreateFilter(args []interface{}) (filters.Filter, error) {
rf := &RetryFilter{}

if config, ok := args[0].(string); !ok {
return nil, fmt.Errorf("filter %q requires single string argument", s.Name())
} else if err := yaml.Unmarshal([]byte(config), rf); err != nil {
return nil, fmt.Errorf("failed to parse configuration: %w", err)
}

switch rf.Type {
case single:
i := 0
rf.Check = func(rsp *http.Response) bool {
i++
if i > rf.MaxTimes {
return false
}
return shouldRetry(rsp.StatusCode, rf.StatusCodes)
}
}

return rf, nil
}

// copy from proxy.shouldLog
func shouldRetry(statusCode int, prefixes []int) bool {
if len(prefixes) == 0 {
return false
}

match := false
for _, prefix := range prefixes {
switch {
case prefix < 10:
match = (statusCode >= prefix*100 && statusCode < (prefix+1)*100)
case prefix < 100:
match = (statusCode >= prefix*10 && statusCode < (prefix+1)*10)
default:
match = statusCode == prefix
}
if match {
break
}
}
return match
}

func (retry) Name() string { return filters.RetryName }
func (retry) CreateFilter([]interface{}) (filters.Filter, error) { return retry{}, nil }
func (retry) Response(filters.FilterContext) {}
func (rf *RetryFilter) Response(filters.FilterContext) {}

func (retry) Request(ctx filters.FilterContext) {
ctx.StateBag()[filters.RetryName] = struct{}{}
func (rf *RetryFilter) Request(ctx filters.FilterContext) {
ctx.StateBag()[filters.RetryName] = rf.Check
}

0 comments on commit 0a27cce

Please sign in to comment.