/
filter.go
86 lines (67 loc) · 1.65 KB
/
filter.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package loadbalancer
import (
"fmt"
"github.com/zalando/skipper/filters"
"math/rand"
)
const (
DecideFilterName = "lbDecide"
DecisionHeader = "X-Load-Balancer-Member"
)
type counter chan int
type decideSpec struct{}
type decideFilter struct {
group string
size int
counter counter
}
func newCounter(size int) counter {
c := make(counter, 1)
c <- rand.Intn(size)
return c
}
func (c counter) inc(groupSize int) int {
v := <-c
c <- v + 1
return v % groupSize
}
func (c counter) value() int {
v := <-c
c <- v
return v
}
// NewDecide create a filter specification for the decision route in
// load balancing scenarios. It expects two arguments: the name of the
// load balancing group, and the size of the load balancing group.
func NewDecide() filters.Spec { return &decideSpec{} }
func (s *decideSpec) Name() string { return DecideFilterName }
func (s *decideSpec) CreateFilter(args []interface{}) (filters.Filter, error) {
if len(args) != 2 {
return nil, filters.ErrInvalidFilterParameters
}
group, ok := args[0].(string)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
size, ok := args[1].(int)
if !ok {
fsize, ok := args[1].(float64)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
size = int(fsize)
}
if size < 1 {
return nil, filters.ErrInvalidFilterParameters
}
return &decideFilter{
group: group,
size: size,
counter: newCounter(size),
}, nil
}
func (f *decideFilter) Request(ctx filters.FilterContext) {
current := f.counter.inc(f.size)
ctx.Request().Header.Set(DecisionHeader, fmt.Sprintf("%s=%d", f.group, current))
}
func (f *decideFilter) Response(filters.FilterContext) {}