Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 07:00 UTC
reverseproxy: Allow `0` as weights for `weighted_round_robin` (#6681)
* Allow 0 as weights Change positive to non-negative * reverseproxy: allow 0 as weighted round robin value * test: add more wrr select test --------- Co-authored-by: peanutduck <peanutduck@yahoo.com>
Sucipto committed
Nov 8, 2024 at 05:58 UTC
825fe48e0654dc6e4e065df364a51ea79488e44b
2 files changed
+65
-6
modules/caddyhttp/reverseproxy/selectionpolicies.go
+13
-6
@@ -111,8 +111,8 @@ func (r *WeightedRoundRobinSelection) UnmarshalCaddyfile(d *caddyfile.Dispenser)
111
if err != nil {
112
return d.Errf("invalid weight value '%s': %v", weight, err)
113
}
114
- if weightInt < 1 {
115
- return d.Errf("invalid weight value '%s': weight should be non-zero and positive", weight)
114
+ if weightInt < 0 {
115
+ return d.Errf("invalid weight value '%s': weight should be non-negative", weight)
116
}
117
r.Weights = append(r.Weights, weightInt)
118
}
@@ -136,8 +136,15 @@ func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request,
136
return pool[0]
137
}
138
var index, totalWeight int
139
+ var weights []int
140
+
141
+ for _, w := range r.Weights {
142
+ if w > 0 {
143
+ weights = append(weights, w)
144
+ }
145
+ }
146
currentWeight := int(atomic.AddUint32(&r.index, 1)) % r.totalWeight
140
- for i, weight := range r.Weights {
147
+ for i, weight := range weights {
148
totalWeight += weight
149
if currentWeight < totalWeight {
150
index = i
@@ -145,9 +152,9 @@ func (r *WeightedRoundRobinSelection) Select(pool UpstreamPool, _ *http.Request,
152
}
153
}
154
148
- upstreams := make([]*Upstream, 0, len(r.Weights))
149
- for _, upstream := range pool {
150
- if !upstream.Available() {
155
+ upstreams := make([]*Upstream, 0, len(weights))
156
+ for i, upstream := range pool {
157
+ if !upstream.Available() || r.Weights[i] == 0 {
158
continue
159
}
160
upstreams = append(upstreams, upstream)
modules/caddyhttp/reverseproxy/selectionpolicies_test.go
+52
@@ -131,6 +131,58 @@ func TestWeightedRoundRobinPolicy(t *testing.T) {
131
}
132
}
133
134
+func TestWeightedRoundRobinPolicyWithZeroWeight(t *testing.T) {
135
+ pool := testPool()
136
+ wrrPolicy := WeightedRoundRobinSelection{
137
+ Weights: []int{0, 2, 1},
138
+ totalWeight: 3,
139
+ }
140
+ req, _ := http.NewRequest("GET", "/", nil)
141
+
142
+ h := wrrPolicy.Select(pool, req, nil)
143
+ if h != pool[1] {
144
+ t.Error("Expected first weighted round robin host to be second host in the pool.")
145
+ }
146
+
147
+ h = wrrPolicy.Select(pool, req, nil)
148
+ if h != pool[2] {
149
+ t.Error("Expected second weighted round robin host to be third host in the pool.")
150
+ }
151
+
152
+ h = wrrPolicy.Select(pool, req, nil)
153
+ if h != pool[1] {
154
+ t.Error("Expected third weighted round robin host to be second host in the pool.")
155
+ }
156
+
157
+ // mark second host as down
158
+ pool[1].setHealthy(false)
159
+ h = wrrPolicy.Select(pool, req, nil)
160
+ if h != pool[2] {
161
+ t.Error("Expect select next available host.")
162
+ }
163
+
164
+ h = wrrPolicy.Select(pool, req, nil)
165
+ if h != pool[2] {
166
+ t.Error("Expect select only available host.")
167
+ }
168
+ // mark second host as up
169
+ pool[1].setHealthy(true)
170
+
171
+ h = wrrPolicy.Select(pool, req, nil)
172
+ if h != pool[1] {
173
+ t.Error("Expect select first host on availability.")
174
+ }
175
+
176
+ // test next select in full cycle
177
+ expected := []*Upstream{pool[1], pool[2], pool[1], pool[1], pool[2], pool[1]}
178
+ for i, want := range expected {
179
+ got := wrrPolicy.Select(pool, req, nil)
180
+ if want != got {
181
+ t.Errorf("Selection %d: got host[%s], want host[%s]", i+1, got, want)
182
+ }
183
+ }
184
+}
185
+
186
func TestLeastConnPolicy(t *testing.T) {
187
pool := testPool()
188
lcPolicy := LeastConnSelection{}